Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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': 
    print(i)

'a'
'b'
'c'

But in a comprehension:

>>> [i for i in 'a','b','c']
  File "<stdin>", line 1
    [i for i in 'a','b','c']
                   ^
SyntaxError: invalid syntax

Is there a reason for this? I wasn't sure about the correct terminology, so my searches yielded nothing useful.

Update:

Per the comments, this syntax is valid for Python 2.x, but not for Python 3.x.

like image 567
LMc Avatar asked Dec 13 '16 17:12

LMc


People also ask

Why tuple comprehension is not possible in Python?

There is no tuple comprehension in Python. Comprehension works by looping or iterating over items and assigning them into a container, a Tuple is unable to receive assignments.

Is there tuple comprehension?

There is no tuple comprehension in Python, but you can get the desired result by using a generator expression and converting the generator object to a tuple, e.g. my_tuple = tuple(int(element) for element in ('1', '3', '5')) .

Can you loop through a tuple in Python?

Loop Through a TupleYou can loop through the tuple items by using a for loop.

Can you use a tuple in a for loop?

Python Tuple – Iterate using For Loop To iterate over the items present in a Python Tuple, you can use for loop statement. The tuple variable returns an iterator and when used with Python For Loop, you can access each item of the tuple during respective iteration.


2 Answers

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 for i in '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.

like image 21
jwodder Avatar answered Oct 17 '22 19:10

jwodder


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 in 0, 1, 2)
  File "<stdin>", line 1
SyntaxError: 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:

  • From List Comprehensions to Generator Expressions
like image 154
ekhumoro Avatar answered Oct 17 '22 17:10

ekhumoro