[Python-ideas] Is this PEP-able? for X in ListY while conditionZ:

Oscar Benjamin oscar.j.benjamin at gmail.com
Thu Jun 27 14:19:33 CEST 2013


On 27 June 2013 12:28, Andrew Barnert <abarnert at yahoo.com> wrote:
> From: Oscar Benjamin <oscar.j.benjamin at gmail.com>
>
> Some of the ideas can only break out of the last loop, some can only break out of all of them, some can break out of any one loop. I don't think it will make a difference that often in comprehensions. A comprehension with two for clauses and an if is already pushing the limits of readability; throwing in a break or return as well just seems like asking for trouble.

So what about Nick's suggestion that a syntax could be limited to
cases where there is only one for clause?

>>>      def stop(): raise StopIteration
>>>
>>>      x = [value if pred(value) else stop() for value in iterable]
>>
>> I prefer
>>
>> x = [value for value in iterable if pred(value) or stop()]
>>
>> so that the flow control is all on the right hand side of the "in".
>
> I suppose this solution allows either. Personally, I think using or for non-trivial flow control is more obscure than helpful. Would you write this?
>
>     for value in iterable:
>         if pred(value) or stop():
>             yield value

No, but I find it readable in the comprehension.

>>>  2. Just require comprehensions to handle StopIteration.
>>>
>>>  The main cost and benefit are the same as #1.
>>>
>>>  However, it makes the language and implementation more complex, rather than
>> simpler.
>>>
>>>  Also, the effects of this less radical change (you can no longer pass
>>> StopIteration through a comprehension) seem like they might be harder to explain
>>> to people than the more radical one.
>>
>> I think that the current behaviour is harder to explain.
>
> What's hard to explain about the current behavior? StopIteration passes through comprehensions the same way it does through for loops.

It's hard to explain the difference between list(generator expression)
and a list comprehension in this respect as it requires thinking about
the mechanics of StopIteration. You can see my previous attempt here:
http://mail.python.org/pipermail/python-ideas/2013-January/019051.html

>>>  7. Add a "magic" while clause that's basically until with the
>> opposite sense.
>>>
>>>      x = [value for value in iterable while pred(value)]
>>>
>>>  This reads pretty nicely (at least in trivial comprehensions), it parallels
>>> takewhile and friends, and it matches a bunch of other languages (most of the
>>> languages where "when" means "if", "while" means
>>> this).
>>>
>>>  But it has a completely different meaning from while statements, and in
>>> fact a barely-related one.
>>>>  Imagine trying to teach that to a novice.
>>
>> I can definitely imagine teaching it to a novice. I have taught Python
>> to groups of students who are entirely new to programming and also to
>> groups with prior experience of other languages. I would not teach
>> list comprehensions by unrolling them unless it was a more advanced
>> Python programming course.
>
> This makes perfect sense today. Going from novice to intermediate understanding of list comprehensions, and many other areas of Python, is almost trivial, and that's part of what makes teaching Python so much easier than teaching, say, C++.
>
> I've seen hundreds of people show up on StackOverflow and similar places completely baffled by a complex list comprehension in some code they've run into. As soon as you show them how to unroll it, they immediately get it. If that were no longer true, how would you get people over that step?

I think that this is really a style problem. The emphasis on unrolling
comprehensions makes it seem acceptable to write complex
comprehensions that can only be understood after being unrolled.

To me, a comprehension is good when you can look at it and immediately
know what it does. If it needs to be mentally unrolled before it can
be understood then it would probably be better if it was actually
unrolled in the source and then everyone can look directly at the
unrolled code.

>>>      x = [value for value in iterable if pred(value) else break]
>>>
>>>  This one is pretty easy to define rigorously, since it maps to exactly what
>> the while attempt maps to with a slight change to the existing rules.
>>>
>>>  But to me, it makes the code a confusing mess. I'm immediately reading
>> "iterable if pred(value) else break", and that's wrong.
>>
>> You wouldn't have that confusion with "else return".
>
> Why not? They're both single-keyword flow-control statements. Why would anyone's brain read else return any differently from else break?

My bad, you're right. I was thinking of the break as an expression
because of the way you split it out but it's not a valid expression
(just like return).


Oscar


More information about the Python-ideas mailing list