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