Почему вы можете прокручивать неявный кортеж в цикле for, но не понимать Python?

Есть ли причина, почему цикл в неявном кортеже в цикле 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.

Ответы

Ответ 1

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

С помощью методов for-loops и list не существует двусмысленности при использовании кортежа без круглых скобок, поскольку первый всегда заканчивается двоеточием, а второй - закрывающей скобкой или ключевым словом 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:

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

Ответ 2

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

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

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

'a', 'b', 'c' наиболее определенно является expression_list, поэтому это работает.

Однако во втором случае встроенные квадратные скобки inline 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

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

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

Где граница между элементами? Является ли это массивом из трех элементов: генератора и целых чисел? Вот так:

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

for не имеет такой двусмысленности, поэтому он не требует скобок.