lambda函数的列表或生成器在Python中不会返回相同的结果

Jac*_*din 2 python functional-programming python-3.x

当我做:

def create_funcs():
    return (lambda: i for i in range(5))

for f in create_funcs():
    print(f())
Run Code Online (Sandbox Code Playgroud)

我得到了预期的:

1
2
3
4
Run Code Online (Sandbox Code Playgroud)

但当我这样做时:

def create_funcs():
    return [lambda: i for i in range(5)]

for f in create_funcs():
    print(f())
Run Code Online (Sandbox Code Playgroud)

我觉得很奇怪:

4
4
4
4
Run Code Online (Sandbox Code Playgroud)

有谁能解释为什么?

Bre*_*arn 6

您的lambda函数i从周围范围捕获变量.正如在这个问题中所描述的那样,范围是理解的范围.

您的循环一次迭代生成器中的项目,并在推进生成器之前调用每个项目.当你得到第一个函数时,生成器暂停在一个i0 的状态,这是函数看到的值.当你推进生成器时,它设置i为1,你得到一个抓取该值的函数.发生器"等待"改变,i直到你进入下一个功能.

在列表理解中,您可以立即获得所有功能.但是所有人仍然i在理解范围内引用相同的变量.由于列表理解会一直到最后,i所以在你有机会使用任何函数之前一直到4.

在这两种情况下,lambda都引用了理解范围中的变量.只是在生成器理解中,这个变量在你已经调用了前一个函数之后才会前进.如果存储第一个函数,则可以看到与list-comprehension案例类似的行为,但在再次推进生成器之前不要调用它:

def create_funcs():
    return (lambda: i for i in range(5))

gen = create_funcs()
f1 = next(gen)
f2 = next(gen)
print(f1())
print(f2())
Run Code Online (Sandbox Code Playgroud)

输出是

1
1
Run Code Online (Sandbox Code Playgroud)

自从我提出的发电机,i是1,所以无论f1f2发现价值被调用时.如果你这样做for f in list(create_funcs()),你可以看到同样的事情,迫使生成器一直到列表理解的结尾.