闭包:
闭包(closure)是函数式编程的重要的语法结构。不同的语言实现闭包的方式不同。Python以函数对象为基础,为闭包这一语法结构提供支持的 (我们在特殊方法与多范式中,已经多次看到Python使用对象来实现一些特殊的语法)。Python一切皆对象,函数这一语法结构也是一个对象。在函数对象中,我们像使用一个普通对象一样使用函数对象,比如更改函数对象的名字,或者将函数对象作为参数进行传递。
- 在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。(相当于给内部函数起别名)
- 实现规则:
定义内部函数
外部函数必须有返回值,而且返回值必须为内部函数对象
# 内嵌的函数
# 1.内部函数引用了外部函数的变量 2.外部函数返回的是内部函数的引用
def outerfunc():
x = 100 # 局部变量
def innerfunc():
z = x+1
return z
return innerfunc
# 函数的局部变量的生命周期,在函数执行完之后,局部变量的内存会被释放
# 但是python中的闭包结构,不一样,他提供了机制保存内部函数引用到的外部函数里的临时变量的对象
f = outerfunc()
print(f())
小问题
def outer():
return [lambda x: i * x for i in range(4)]
print([m(2) for m in outer()])
结果为:[6,6,6,6],而期望是[0,2,4,6]
修改后:
def outer():
return [lambda x,i=i: i * x for i in range(4)]
print([m(2) for m in outer()])
#使用生成器
def outer():
for i in range(4):
yield lambda x : i*x
print([m(2) for m in outer()])
结果为:[0, 2, 4, 6]
为什么会出现这种问题:
原因是Python的闭包是延迟绑定(late binding)的。这表明在闭包中使用的变量直到内层函数被调用的时候才会被查找。结果是,当调用multipliers()返回的函数时,i参数的值会在这时被在调用环境中查找。所以,无论调用返回的哪个函数,for循环此时已经结束,i等于它最终的值3。因此,所有返回的函数都要乘以传递过来的3,因为上面的代码传递了2作为参数,所以他们都返回了6(即,3 * 2)