Skip to content Skip to sidebar Skip to footer

Why Can You Loop Through An Implicit Tuple In A For Loop, But Not A Comprehension In Python?

Is there a reason why looping through an implicit tuple in a for loop is okay, but when you do it in a comprehension you get a syntax error? For example: for i in 'a','b','c':

Solution 1:

This changed in Python3, mainly in order to make list comprehensions more consistent with generator expressions.

With for-loops and list comprehensions, there is no ambiguity when using a tuple with no parentheses, because the former is always terminated by a colon, and the latter by either a closing bracket or a for/if keyword.

However, part of the design of generator expressions requires that they can be used "bare" as function arguments:

>>> list(i for i in range(3))
[0, 1, 2]

which creates some ambiguity for unparenthesized tuples, because any commas may introduce a new argument:

>>> list(i for i in0, 1, 2)
  File"<stdin>", line 1SyntaxError: Generator expression must be parenthesized if not sole argument

So tuples must always be parenthesized in generator expressions, and the same restriction now also applies to list comprehensions in order to preserve consistency.

PS:

Guido van Rossum wrote a article that spells out all the details on this subject in his History of Python blog:

Solution 2:

Because the for i in in the first code is a different syntactical construction than the for i in in the second code.

The first case is a for statement, which has the grammar:

for_stmt ::=  "for" target_list "in" expression_list ":" suite
             ["else"":" suite]

'a', 'b', 'c' is most definitely an expression_list, so that works out.

In the second case, however, the inline for inside square brackets forces the code to be interpreted as a list comprehension, and in Python 3, list comprehensions must have the syntax:

comprehension ::=  expression comp_for
comp_for      ::=  "for" target_list "in" or_test [comp_iter]
comp_iter     ::=  comp_for | comp_if
comp_if       ::=  "if" expression_nocond [comp_iter]

Note that the part after the in must be an or_test, yet comma-delimited expressions create expression lists, and an expression list cannot be an or_test --- or, put another way, or has higher precedence than comma. Python thus thinks the comprehension ends at the comma, so that the three elements of the list are:

i foriin'a''b''c'

which (unless you put the i for i in 'a' in parentheses) is obviously invalid.

As to why this works in Python 2 ... I'm still looking.

Solution 3:

I think the problem is here: in the latter case it is not so obvious which objects are you iterating:

>>> [i for i in ('a','b','c')]['a', 'b', 'c']

Where's a border between elements? Is it an array of 3 elements: generator and 2 integers? Like this:

>>> [(i for i in 'a'),'b','c'][<generator object <genexpr> at 0x10cefeeb8>, 'b', 'c']

for doesn't have such ambiguity - so it doesn't need parenthesis.

Post a Comment for "Why Can You Loop Through An Implicit Tuple In A For Loop, But Not A Comprehension In Python?"