此行为已在 python 3 中修复。当您使用列表解析[i(0) + i(1) for a in alist] 时,您将在其周围范围内定义a,i 可以访问该范围。在新会话中list(i(0) + i(1) for a in alist) 会抛出错误。
>>> i = lambda x: a[x]
>>> alist = [(1, 2), (3, 4)]
>>> list(i(0) + i(1) for a in alist)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
File "<stdin>", line 1, in <lambda>
NameError: global name 'a' is not defined
列表推导式不是生成器:Generator expressions and list comprehensions。
生成器表达式被括号(“()”)和列表包围
推导式用方括号(“[]”)括起来。
在您的示例中,list() 作为一个类具有自己的变量范围,并且最多可以访问全局变量。当您使用它时,i 将在该范围内查找 a。在新会话中试试这个:
>>> i = lambda x: a[x]
>>> alist = [(1, 2), (3, 4)]
>>> [i(0) + i(1) for a in alist]
[3, 7]
>>> a
(3, 4)
在另一个会话中将其与此进行比较:
>>> i = lambda x: a[x]
>>> alist = [(1, 2), (3, 4)]
>>> l = (i(0) + i(1) for a in alist)
<generator object <genexpr> at 0x10e60db90>
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> [x for x in l]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
File "<stdin>", line 1, in <lambda>
NameError: global name 'a' is not defined
当您运行list(i(0) + i(1) for a in alist) 时,您会将生成器(i(0) + i(1) for a in alist) 传递给list 类,它会在返回列表之前尝试将其转换为自己范围内的列表。对于这个在 lambda 函数内部没有访问权限的生成器,变量a 没有意义。
生成器对象<generator object <genexpr> at 0x10e60db90> 丢失了变量名a。然后当list 尝试调用生成器时,lambda 函数将为未定义的a 抛出错误。
列表推导式与生成器相比的行为也提到了here:
列表推导式也将它们的循环变量“泄漏”到
周边范围。这也将在 Python 3.0 中发生变化,因此
Python 3.0 中列表推导的语义定义将是
相当于列表()。 Python 2.4 及更高版本
如果列表理解的循环应该发出弃用警告
变量与立即使用的变量同名
周围的范围。
在python3中:
>>> i = lambda x: a[x]
>>> alist = [(1, 2), (3, 4)]
>>> [i(0) + i(1) for a in alist]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
File "<stdin>", line 1, in <lambda>
NameError: name 'a' is not defined