This question already has answers here:
Local variables in nested functions
(4个答案)
7年前关闭。
我偶然发现了我很难理解的python行为。这是概念验证代码:
上面的输出是:
上面的行为与其中带有for循环的成熟函数相同(因此,它不是列表理解语法)。
但是,请耐心等待:还有更多……还有更多令人困惑的地方!
以下脚本的工作方式类似于
(输出:
但是,请注意将变量名
(输出:
对这里发生的事情有任何想法吗?我怀疑肯定有一些与我的解释器的底层C实现有关的陷阱,但是我没有别的东西(Jthon,PyPy或类似的东西)来测试这种行为在不同实现之间是否一致。
按照所谓的LEGB rule。
到
您已经找到了一种解决方法,可以使用诸如
(4个答案)
7年前关闭。
我偶然发现了我很难理解的python行为。这是概念验证代码:
from functools import partial
if __name__ == '__main__':
sequence = ['foo', 'bar', 'spam']
loop_one = lambda seq: [lambda: el for el in seq]
no_op = lambda x: x
loop_two = lambda seq: [partial(no_op, el) for el in seq]
for func in (loop_one, loop_two):
print [f() for f in func(sequence)]
上面的输出是:
['spam', 'spam', 'spam']
['foo', 'bar', 'spam']
loop_one
的行为令我感到惊讶,因为我希望它的行为像loop_two
一样:el
是一个不变的值(字符串),在每个循环中都会更改,但是 lambda
似乎存储了指向“循环变量” 的指针,例如循环是否为序列的每个元素循环使用相同的内存地址。上面的行为与其中带有for循环的成熟函数相同(因此,它不是列表理解语法)。
但是,请耐心等待:还有更多……还有更多令人困惑的地方!
以下脚本的工作方式类似于
loop_one
:b = []
for foo in ("foo", "bar"):
b.append(lambda: foo)
print [a() for a in b]
(输出:
['bar', 'bar']
)但是,请注意将变量名
foo
替换为a
时会发生什么:b = []
for a in ("foo", "bar"):
b.append(lambda: a)
print [a() for a in b]
(输出:
[<function <lambda> at 0x25cce60>, <function <lambda> at 0x25cced8>]
)对这里发生的事情有任何想法吗?我怀疑肯定有一些与我的解释器的底层C实现有关的陷阱,但是我没有别的东西(Jthon,PyPy或类似的东西)来测试这种行为在不同实现之间是否一致。
最佳答案
lambda: el
中使用的函数loop_one
引用了在本地范围中 undefined variable el
。因此,Python在另一个lambda
的封闭范围内寻找它:
lambda seq: [lambda: el for el in seq]
按照所谓的LEGB rule。
到
lambda: el
调用时,这个封闭的lambda(当然)已经被调用,并且列表理解已经得到评估。列表推导中使用的el
是此封闭lambda中的局部变量。它的值是当Python在el
中查找lambda: el
的值时返回的值。对于列表理解中所有不同的el
函数,lambda: el
的值是相同的:这是el
循环中分配给for el in seq
的最后一个值。因此,el
始终是'spam'
,是seq
中的最后一个值。您已经找到了一种解决方法,可以使用诸如
loop_two
之类的闭包。另一种方法是将el
定义为具有默认值的局部变量:loop_one = lambda seq: [lambda el=el: el for el in seq]
关于python - 循环中的奇怪lambda行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19768456/
10-16 17:29