[Python-ideas] Generator syntax hooks?

Nick Coghlan ncoghlan at gmail.com
Fri Aug 11 00:34:53 EDT 2017


On 11 August 2017 at 01:39, Paul Moore <p.f.moore at gmail.com> wrote:
> On 10 August 2017 at 14:42, Steven D'Aprano <steve at pearwood.info> wrote:
>> I don't think it is confusing. Regardless of the implementation, the
>> meaning of:
>>
>> [expression for x in sequence while condition]
>>
>> should (I believe) be obvious to anyone who already groks comprehension
>> syntax. The mapping to a for-loop is admittedly a tad more complex:
>>
>> result = []
>> for x in sequence:
>>     if not condition: break
>>     result.append(expression)
>>
>> but I'm yet to meet anyone who routinely and regularly reads
>> comprehensions by converting them to for loops like that. And if they
>> did, all they need do is mentally map "while condition" to "if not
>> condition: break" and it should all Just Work™.
>
> The hard part is the interaction between if and while.
>
> Consider (expr for var in seq if cond1 while cond2):
>
> This means:
>
> for var in seq:
>     if cond1:
>         if not cond2: break
>         yield expr
>
> Note that unlike all other comprehension clauses (for and if) while
> doesn't introduce a new level of nesting. That's an inconsistency, and
> while it's minor, it would need clarifying (my original draft of this
> email was a mess, because I misinterpreted how if and while would
> interact, precisely over this point).

This is actually how I came to the conclusion that if we were ever to
do something like this, the termination condition would need to go
*before* the filter condition:

    (expr for var in seq while loop_cond if filter_cond)

    <=>

    for var in seq:
        if loop_cond:
            if filter_cond:
                yield expr
        else:
            break

With the clauses in that order, the "while" keyword effectively
operates as "if-else-break" the same way it does in a regular while
loop, and could potentially be introduced as a modifying clause on
regular for loops at the same time.

One of the neat things the latter would allow is to make it even
easier to introduce a diagnostic loop counter into while loops:

    while condition:
        ...

could become:

    for iteration in itertools.count(1) while condition:
        ...

rather than having to implement a manually incremented loop counter
the way you do today.

> Also, there's a potential issue
> here - consider
>
>     [expr for var in even_numbers() if is_odd(var) while var < 100]
>
> This is an infinite loop, even though it has a finite termination
> condition (var < 100), because we only test the termination condition
> if var is odd, which it never will be.

This is another good reason why a termination condition would need to
be checked before the filter condition rather than either after it, or
only when the filter condition was true.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list