Proposed new syntax

Steve D'Aprano steve+python at pearwood.info
Fri Aug 18 20:16:45 EDT 2017


On Thu, 17 Aug 2017 03:54 pm, Marko Rauhamaa wrote:

> Ben Finney <ben+python at benfinney.id.au>:
> 
>> The Python list comprehension syntax does not specify control flow.
> 
> I understand your point, but how do you know your statement is true?
> 
> I didn't check this, but I would imagine the list comprehension:
> 
>    [ f(x) for x in I if c(x) ]
> 
> was defined as syntactic sugar for:
> 
>    list(f(x) for x in I if c(x))

Not originally. List comprehensions were added to Python in version 2.0, before
generator expressions. (Generator expressions only made it into the language in
version 2.4.)

But right from 2.0, they have been explicitly defined as equivalent to for
loops:

https://github.com/python/cpython/blob/6f0eb93183519024cb360162bdd81b9faec97ba6/Doc/whatsnew/2.0.rst#list-comprehensions

In Python 3, it would make sense for list/set/dict comprehensions to be thin
wrappers around generator expressions, but I don't know if they share
implementations that way or have separate "copy and paste" implementations. I
can't find where they are implemented.

This does leave a *tiny* bit of wriggle-room: the implementation (in C, say, or
some other language) doesn't have to use a for-loop. It could use recursion, or
a while-loop, or it might unroll the loop into a long series of imperative
statements, or use GOTO to emulate looping. So long as the Python semantics
remain the same, and the elements are generated in the same order.


> where
> 
>    f(x) for x in I if c(x)
> 
> has heavily iterative semantics.

Indeed. For loops are one of the cardinal examples of iteration. It isn't a
coincidence that generator expressions and comprehensions use the same syntax.

Whatever implementation is used, the semantics must be the same as the
equivalent for loop procedural code. For example:


from io import StringIO
myfile = StringIO('Is this the room for an argument?')
values = [myfile.read(1) for i in range(33)]
assert values == list('Is this the room for an argument?')


Python is not free to generate the results in some other order.



>> List comprehensions, in their syntax, strongly connote a single
>> declarative operation. This makes them different from iteration
>> syntax.
> 
> Except for side effects, you get the same result whichever way you
> imagine it.

That's not correct, as the example of reading from a file demonstrates.


> As a side not, I have found it rather confusing that I have to say:
> 
>   [ (x, y) for x in range(5) for y in range(x) ]
> 
> instead of:
> 
>   [ (x, y) for y in range(x) for x in range(5) ]

That doesn't work because x isn't defined when you call range(x).


> After all, you must say:
> 
>   [ ((x, y) for y in range(x)) for x in range(5) ]
> 
> which, admittedly, means a different thing.

Indeed. Completely different.




-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list