[Python-Dev] The `for y in [x]` idiom in comprehensions

Chris Angelico rosuav at gmail.com
Sun Feb 25 10:08:49 EST 2018


On Mon, Feb 26, 2018 at 12:11 AM, Nikolaus Rath <Nikolaus at rath.org> wrote:
> On Feb 25 2018, Chris Angelico <rosuav at gmail.com> wrote:
>> On Sun, Feb 25, 2018 at 11:02 PM, Nikolaus Rath <Nikolaus at rath.org> wrote:
>>> On Feb 22 2018, Serhiy Storchaka <storchaka at gmail.com> wrote:
>>>> 1. Inner generator expression:
>>>>
>>>>     result = [y + g(y) for y in (f(x) for x in range(10))]
>>>>
>>> [...]
>>>>
>>>> And maybe there are other ways.
>>>
>>> I think the syntax recently brough up by Nick is still the most
>>> beautiful:
>>>
>>>     result = [ (f(x) as y) + g(y) for x in range(10)]
>>>
>>> ..but I wonder if it is feasible to make the interpreter sufficiently
>>> smart to evaluate the first summand before the second.
>>
>> It already has to. The order of evaluation in Python is well defined,
>> mostly "left to right".
>
> Ah, then the problem is how to evaluate
>
>     result = [ y + g(f(x) as y) for x in range(10)]
>

That ought to raise UnboundLocalError, since y is evaluated before g's
arguments. If you're reusing an expression, it isn't too much hassle
to demand that the *first* instance of that expression be the one with
the 'as' clause. Generally "first" means "leftmost", with rare
exceptions (eg it'd be "y if (expr as y) else y" with the assignment
in the middle), so that shouldn't bother most people.

>> But if you allow this in a comprehension, the
>> obvious next step will be "do we allow this in ANY expression?"
>
> Yes, of course. After all, IIRC Nick proposed it to simplify ternary
> expressions.

The trouble with allowing 'expr as name' in any context is that it's
pretty much guaranteed to create confusion in a 'with' statement.
Compare:

with open(fn) as f:
with (open(fn) as f):
with contextlib.closing(open(fn)) as f:
with (contextlib.closing(open(fn)) as f):

Do they all do the same thing? Can you see at a glance which one is
different, and *how* it's different?

And I'm sure there are other situations where it would be similarly
confusing, yet still potentially useful. Does this just get filed
under "consenting adults"?

Speaking as a C programmer who's quite happy to write code like "while
((var = func()) != sentinel)", I wouldn't object to this coming up in
Python; the "as name" syntax has the huge advantage over C's syntax in
that you can't accidentally leave off one equals sign and get the
wrong behaviour. But I know that a lot of people dislike this at a
more fundamental level.

If someone wants to push for this, I think it probably needs a PEP -
it's a point that comes up periodically. I don't think it's ever had a
PEP written about it, but it's a bit hard to search for; maybe someone
else knows off hand?

ChrisA


More information about the Python-Dev mailing list