[Python-Dev] Disallow ambiguous syntax f(x for x in [1],)

Serhiy Storchaka storchaka at gmail.com
Sun Nov 12 10:17:51 EST 2017


Initially generator expressions always had to be written inside 
parentheses, as documented in PEP 289 [1]. The additional parenthesis 
could be omitted on calls with only one argument, because in this case 
the generator expression already is written inside parentheses. You 
could write just `list(x for x in [1])` instead of `list((x for x in 
[1]))`. The following code was an error:

 >>> list(x for x in [1], *[])
   File "<stdin>", line 1
SyntaxError: invalid syntax
 >>> list(x for x in [1],)
   File "<stdin>", line 1
SyntaxError: invalid syntax

You needed to add explicit parenthesis in these cases:

 >>> list((x for x in [1]), *[])
[1]
 >>> list((x for x in [1]),)
[1]

But in Python 2.5 the following examples were accepted:

 >>> list(x for x in [1], *[])
[1]
 >>> list(x for x in [1], *{})
[1]
 >>> list(x for x in [1],)
[1]

However I haven't found anything about this change in the "What's New In 
Python 2.5" document [2].

The former two cases were found to be a mistake and it was fixed in 
Python 3.5.

 >>> list(x for x in [1], *[])
   File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
 >>> list(x for x in [1], *{})
   File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument

But `list(x for x in [1],)` still is accepted. I think it would be 
better it this raises a SyntaxError.

1. This syntax is ambiguous, because at first look it is not clear 
whether it is equivalent to `list((x for x in [1]),)` or to `list(x for 
x in ([1],))`.

2. It is bad from the aesthetic point of view, because this is the only 
case when the generator expression has not written inside parentheses. I 
believe that allowing to omit parenthesis in a call with a single 
generator expression argument was caused by aesthetic reasons.

3. I believe the trailing comma in function call was allowed because 
this simplified adding, removing and commenting out arguments.

     func(first_argument,
          second_argument,
          #third_argument,
         )

You shouldn't touch other lines by adding or removing a comma when add 
or remove arguments. But this reason is not applicable to the case of 
`list((x for x in [1]),)`, because the generator expression without 
parenthesis should be the only argument. Therefore there is no reasons 
to allow this syntax.

4. 2to3 didn't supported this syntax for recent times [4]. Finally it 
was changed, but I think that it would be better to disallow this syntax 
for reasons mentioned above.

[1] https://www.python.org/dev/peps/pep-0289/
[2] https://docs.python.org/2.5/whatsnew/whatsnew25.html
[3] https://docs.python.org/3.5/whatsnew/3.5.html#changes-in-python-behavior
[4] https://bugs.python.org/issue27494



More information about the Python-Dev mailing list