Language improvement: Get more from the `for .. else` clause

Victor Savu victor.nicolae.savu at gmail.com
Sun Jun 26 10:05:47 EDT 2016


tl;dr: 1. Add `StopAsyncIteration.value`, with the same semantic as
       `StopIteration.value` (documented in PEP 380).
       2. Capture `StopIteration.value` and StopAsyncIteration.value in the
       `else` clauses of the `for` and `async for` statements respectively.
Note: I already have a proof-of-concept implementation:
    repository:   https://github.com/Victor-Savu/cpython
    branch: feat/else_capture


Dear members of the Python list,

I am writing to discuss and get the community's opinion on the following two
ideas:

 1. Capture the `StopIteration.value` in the `else` clause of the `for ..
else`
    statement:

    Generators raise StopIteration on the return statement. The exception
    captures the return value. The `for` statement catches the
`StopIteration`
    exception to know when to jump to the optional `else` statement, but
    discards the enclosed return value.

    I want to propose an addition to the Python syntax which gives the
option
    to capture the return value in the `else` statement of the `for` loop:

    ```
    def holy_grenade():
        yield 'One ...'
        yield 'Two ...'
        yield 'Five!'
        return ('Galahad', 'Three')

    for count_ in holy_grenade():
        print("King Arthur: {count_}")
    else knight, correction:  # << new capture syntax here
        print(f"{knight}: {correction}, Sir!")
        print(f"King Arthur: {correction}!")
    ```

    prints:
    ```
    King Arthur: One ...
    King Arthur: Two ...
    King Arthur: Five!
    Galahad: Three, Sir!
    King Arthur: Three!
    ```

    Of course, the capture expression is optional, and omitting it preserves
    the current behavior, making this proposed change backwards compatible.
    Should the iterator end without raising the StopIteration exception,
    the value `None` will be implicitly passed to the capture expression. In
    the example above, this will result in:
    ```
    TypeError: 'NoneType' object is not iterable
    ```
    because of the attempt to de-structure the result into `knight` and
    `correction`.

 2. Add a `StopAsyncIteration.value` member which can be used to transfer
    information about the end of the asynchronous iteration, in the same way
    the `StopIteration.value` member is used (as documented in PEP 380).
    Capture this value in the in the else clause of the `async for`
statement
    in the same way as proposed for the `StopIteration.value` in the
previous
    point.

You can find a working proof-of-concept implementation of the two proposed
changes in my fork of the semi-official cpython repository on GitHub:
    repository: https://github.com/Victor-Savu/cpython
    branch: feat/else_capture

Disclaimer: My Internet searching skills have failed me and I could not find
any previous discussion on any of the two topics. If you are aware of such
discussion, I would be grateful if you could point it out.

I look forward to your feedback, ideas, and (hopefully constructive)
criticism!


Best regards,
Victor


More information about the Python-list mailing list