返回信息流下面的俩例子怎么理解……
源网页:http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0014186131194415d50558b7a1c424f9fb52b84dc9c965c000
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了。
你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果是:
>>> f1()
9
>>> f2()
9
>>> f3()
9
全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。
返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
>>> def count():
... fs = []
... for i in range(1, 4):
... def f(j):
... def g():
... return j*j
... return g
... fs.append(f(i))
... return fs
...
>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9
这是一条镜像帖。来源:北邮人论坛 / python / #6096同步于 2015/4/8
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Python机器人发帖
关于闭包……求教
splendidone
2015/4/8镜像同步6 回复
订阅后,新回复会通过你的通知中心匿名送达。
6 条回复
吓得滚回去看了一眼Python Language Reference https://docs.python.org/3/reference/executionmodel.html#naming-and-binding
Python里面,所有变量都是block作用域。Python里能够创建block的只有模块(.py文件)、函数定义、类定义。一个函数里的变量如果不是引用当前函数块里的变量,都是“自由”变量,所以嵌套函数定义的时候,并不是直接按值绑定这些变量。
所以:
# @xw2423真好,空格的bug修复了以后Python终于可以开心地复制粘贴了
def foo():
a = 42
def bar():
return a # 绑定为foo()里的a,并不是直接绑定为42
a = 43
return bar()
f = foo()
f() # 43
def goo():
a = 42
def gar():
return a # 绑定为goo()里的a,并不是直接绑定为42
del a
return gar()
g = goo()
g() # NameError: free variable 'a' referenced before assignment in enclosing scope
# Python以为你在foo里没给a赋值就先用a了,其实是我把a删了。
所以要想用循环创建多个函数,最好的办法就是再加一层函数了,毕竟Python里能创建block的最轻量级的东西就是函数了(类也行,太麻烦)。
def foo():
def make_bar(j):
def bar():
return j*j
return bar
rv = []
for i in range(1,4):
rv.append(make_bar(i))
return rv
funcs = foo()
for func in funcs:
print(func()) # 1 4 9
Lua的情况好一些,for循环的变量的作用域是for里面,但local变量的作用域是它所在的block。Lua里,所有do..end之间的都是block。
function foo1()
local lst = {}
for i = 1,3 do -- 每次的i都在一个不同的作用域里
local function bar() return i*i end
table.insert(lst,bar)
end
return lst
end
function foo2()
local lst = {}
local i = 1
while i <= 3 do -- 3次绑定的都是同一个i,所以结果都是一样的
local function bar() return i*i end
table.insert(lst,bar)
i = i + 1
end
return lst
end
function foo3()
local lst = {}
local i = 1
while i <= 3 do
local j = i -- i都一样,但每个j都是新的
function bar() return j*j end
table.insert(lst,bar)
i = i + 1
end
return lst
end
fs1 = foo1()
fs2 = foo2()
fs3 = foo3()
for i,f in ipairs(fs1) do print(f()) end -- 1,4,9
for i,f in ipairs(fs2) do print(f()) end -- 16,16,16
for i,f in ipairs(fs3) do print(f()) end -- 1,4,9
>>> def goo():
... a=100
... def bar():
... print a
... del a
... return bar
...
SyntaxError: can not delete variable 'a' referenced in nested scope
>>>
>>> import sys
>>> sys.version
'2.7.6 (default, Jun 22 2015, 17:58:13) \n[GCC 4.8.2]'
【 在 nuanyangyang 的大作中提到: 】
: 吓得滚回去看了一眼Python Language Reference https://docs.python.org/3/reference/executionmodel.html#naming-and-binding
: Python里面,所有变量都是block作用域。Python里能够创建block的只有模块(.py文件)、函数定义、类定义。一个函数里的变量如果不是引用当前函数块里的变量,都是“自由”变量,所以嵌套函数定义的时候,并不是直接按值绑定这些变量。
: 所以:
: ...................
【 在 tycoon0 的大作中提到: 】
: >>> def goo():
: ... a=100
: ... def bar():
: ...................
好像应该是这样的。