此行为已在 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
列表推导不是生成器:生成器表达式和列表推导。
生成器表达式被括号(“()”)包围,列表推导式被方括号(“[]”)包围。
在您的示例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 函数将抛出 undefined 错误a
。
与生成器相比,列表推导的行为也在这里提到:
列表推导还将它们的循环变量“泄漏”到周围的范围内。这在 Python 3.0 中也将发生变化,因此 Python 3.0 中列表推导式的语义定义将等同于 list()。如果列表推导的循环变量与紧邻范围内使用的变量同名,则 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