我偶然发现了一个我很难理解的 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 或类似的)来测试这种行为在不同的实现中是否一致。