2016-12-13 5 views
16

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

Например:

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.

+3

Мне никогда не нравились * неявные кортежи *, поэтому оба выглядят плохо для меня, но вопрос интересный –

+0

Будет ли это ':', который помогает распознать конец неявного кортежа? – LMc

+3

Он работает в Python 2.7, но не в Python 3 –

ответ

23

Это изменение в 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:

3

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

Первый случай a for statement, which has the grammar:

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

'a', 'b', 'c' наиболее определенно expression_list, так что работает.

Во втором случае, однако, встроенный for внутри квадратных скобки заставляет код, который будет интерпретирована как список понимание, а в 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] 

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

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

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

Как это работает в Python 2 ... Я все еще смотрю.

+0

Явно * недействителен? Python позволяет списки произвольных объектов, таких как '[[1,2],« cat », Date]'. Потенциально путают, конечно. – nigel222

+1

В ответ на [@ ekhumoro] (http://stackoverflow.com/a/41128011/364696) он, вероятно, работал в Python 2, потому что в Python 2 были созданы методы распознавания списков, прежде чем существовали обобщенные синтаксисы понимания и выражения генератора. Они не вели себя как генераторные выражения, установки/диктовки и т. Д., Пропускают переменные в окружающий объем, допускают несравнимые итерации и т. Д. В Python 3 для упрощения и согласованности переписные списки были изменены на нечто более близкое к обертыванию genexpr в конструкторе списка, а пределы genexpr были унаследованы побочным эффектом. – ShadowRanger

+1

Что касается «почему это работает в Python 2»: грамматика явно разрешает списки, разделенные запятыми: ['old_expression'] (https://docs.python.org/2/reference/expressions.html#grammar-token -old_expression'). – dhke

0

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

>>> [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 не имеет такую ​​неоднозначности - поэтому она не нуждается в круглых скобках.