为什么你可以循环遍历for循环中的隐式元组,而不是Python中的理解?

时间:2016-12-13 17:45:55

标签: python python-3.x loops for-loop list-comprehension

是否有理由在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

这有什么理由吗?我不确定正确的术语,所以我的搜索没有任何用处。

更新

根据评论,此语法 对Python 2.x有效,但对Python 3.x无效。

3 个答案:

答案 0 :(得分:23)

这在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撰写了一篇文章,在他的Python博客博客中阐述了有关该主题的所有细节:

答案 1 :(得分: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之后的部分必须是or_test,但逗号分隔的表达式会创建expression lists,而表达式列表不能是or_test ---或者换句话说,or的优先级高于逗号。 Python因此认为理解以逗号结束,因此列表的三个元素是:

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

(除非你将i for i in 'a'括在括号中)显然是无效的。

至于为什么这在Python 2中有用......我还在寻找。

答案 2 :(得分:0)

我认为问题在于:在后一种情况下,你在迭代哪些对象并不是那么明显:

>>> [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没有这种歧义 - 所以它不需要括号。