[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