谁能帮忙解释这段 python 代码中两个函数的运行后的不同结果?

2015-02-27 15:51:20 +08:00
 Fikhtengol
https://gist.github.com/Fikhtengol/704d35b23d603d5bb794
2845 次点击
所在节点    Python
7 条回复
Fikhtengol
2015-02-27 15:52:11 +08:00
结果:
<function gen_func1 at 0x10a2b1578>
first loop: 0
first loop: 1
second loop: 1
second loop: 1
<function gen_func2 at 0x10a2b15f0>
first loop: 0
first loop: 1
second loop: 0
second loop: 1
wwwjfy
2015-02-27 16:22:36 +08:00
关键字:closure
Sylv
2015-02-27 16:41:58 +08:00
应该是 Namespace 命名空间的原因

方法 gen_func1 yield 出两个 callback 方法对象,因为 callback 是由 lambda 创建的,没有自己的命名空间,所以这两个 callback 对象中的变量 i 其实是同一个,都是指向 gen_func1 方法的局部变量 i。在 second loop 的时候这个变量 i 的值是 1,所以两次 print 出来的都是 1。

而方法 gen_func2 yield 出的两个 callback 方法对象,即 genf 方法对象是有自己的命名空间的,所以这两个对象的局部变量 i 不是同一个,也不是 gen_func2 的变量 i。这两个变量 i 在赋值时固定了,所以 second loop 时 print 出 0、1 两个值。
013231
2015-02-27 16:53:11 +08:00
看看下面简化版的代码:

In [42]: func1 = lambda: i

In [43]: i = 0

In [44]: func1()
Out[44]: 0

In [45]: i = 3

In [46]: func1()
Out[46]: 3

In [47]: gen_func2 = lambda j: lambda: j

In [48]: func2 = gen_func2(i)

In [49]: func2()
Out[49]: 3

In [50]: i = 2

In [51]: func2()
Out[51]: 3

能看明白为什么嘛? 原理一样的.
Lime
2015-02-27 17:13:25 +08:00
闭包问题。

简单来说就是gen_func1的i是地址是相同的。

楼主把gen_func1改成如下就就明白了。

def gen_func1(n):
for i in range(n):
callback = lambda i=i: i
yield callback
Lime
2015-02-27 17:21:34 +08:00
alsotang
2015-02-27 17:29:08 +08:00
根据楼上各位的回答,楼主还可以去看看 nonlocal 这个关键词

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/173238

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX