Есть ли причина, по которой циклически проходить через неявный кортеж в цикле for нормально, но когда вы делаете это в понимании, вы получаете синтаксическую ошибку?

Например:

for i in 'a','b','c': 
    print(i)

'a'
'b'
'c'

Но в понимании:

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

Есть причина для этого? Я не был уверен в правильной терминологии, поэтому мои поиски не дали ничего полезного.

< Сильный > Update :

Согласно комментариям, этот синтаксис является действительным для Python 2.x, но не для Python 3.x.

17
LMc 13 Дек 2016 в 20:45

3 ответа

Лучший ответ

Это изменилось в Python3, главным образом для того, чтобы сделать списки более совместимыми с выражениями генератора.

При использовании циклов for и списков не возникает двусмысленности при использовании кортежа без скобок, поскольку первый всегда заканчивается двоеточием, а последний - закрывающей скобкой или ключевым словом for/if.

Однако часть разработки выражений генератора требует, чтобы они могли использоваться «голыми» в качестве аргументов функции:

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

Что создает некоторую неоднозначность для непереносимых кортежей, потому что любые запятые могут вводить новый аргумент:

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

Таким образом, кортежи всегда должны быть заключены в скобки в выражениях генератора, и то же самое ограничение теперь также применяется к спискам, чтобы сохранить последовательность.

PS :

Гидо ван Россум (Guido van Rossum) написал статью, в которой излагаются все детали по этому вопросу в своем блоге History of Python:

23
ekhumoro 13 Дек 2016 в 18:42

Я думаю, что проблема здесь: в последнем случае не так очевидно, какие объекты вы повторяете:

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

Где граница между элементами? Это массив из 3 элементов: генератор и 2 целых числа? Как это:

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

for не имеет такой двусмысленности - поэтому не нуждается в скобках.

0
Eugene Lisitsky 14 Дек 2016 в 16:09

Потому что for i in в первом коде является другой синтаксической конструкцией, чем for i in во втором коде.

Первый случай - это оператор for, который имеет грамматика:

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

'a', 'b', 'c' определенно является expression_list, так что получается.

Во втором случае, однако, встроенные for в квадратных скобках заставляют код интерпретироваться как понимание списка, а в Python 3 списочные выражения должны иметь синтаксис:

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]

Обратите внимание, что часть после in должна быть or_test, но выражения с разделителями-запятыми создают списки выражений, и список выражений не может быть or_test --- или, другими словами, or имеет более высокий приоритет, чем запятая. Таким образом, Python считает, что понимание заканчивается запятой, поэтому три элемента списка:

i for i in 'a'
'b'
'c'

Который (если вы не поместите i for i in 'a' в скобки), очевидно, недействителен.

Что касается того, почему это работает в Python 2 ... Я все еще ищу.

3
jwodder 13 Дек 2016 в 18:22