Python笔录–闭包
1. 定义
Python
的方法在使用时会返回一个对象作为返回值(包括None),本着Python中万物皆对象的原则,将返回值变为一个函数的引用(即C++中的函数指针)会发生什么有趣的事呢。
def out_function():
x = "变量"
def inner_function():
print(x)
return inner_function
if __name__ == "__main__":
inner = out_function() #inner = inner_function
inner() # 输出x
上述代码块(包括out_function和inner_function)就形成了一个闭包,是不是想到了装饰器,其实装饰器的使用就是闭包的一个实例。
闭包: 在外层函数内定义一个内层函数,内层函数使用了外层函数所声明的变量并且外层函数的返回值是内层函数的引用,此时我们称上述代码构成了一个闭包。
2. 特点
通常情况下,一个方法在调用结束后,会被垃圾回收机制处理,从而清除变量,释放内存。但在闭包中,如果外层方法的变量会被内层方法访问,那么外层方法被回收时相应的变量(特指内层方法需要的变量)会被绑定到内层方法的变量上。
上例中inner对应的内层方法需要外层方法的变量x,所以外层方法out_function
被调用后变量x
并未被回收,而是隐式绑定到了inner_function
中。若不绑定,inner = out_function()
执行后,变量x
被释放,执行inner()
会报错,内层方法inner_function并无变量x
。
所以这种隐式绑定是闭包必须提供的服务,也是闭包的一大特色。
3. 改动变量
上面说到内层方法可以调用外层方法的变量,那么可不可以修改变量呢。答案是可以的,但是不能直接修改。不可修改变量不能直接修改,修改时需要转化为可修改变量或使用关键字nolocal
。
def out_function():
x = "variable test1"
y = ["variable test2"]
def inner_function():
#若 y="variable test2" 内函数中直接使用y += "2"会报错,因为y在引用前已经被外层方法所分配、绑定,不属于内层方法
y[0] += "2"
nonlocal x
x += "1"
print(x)
print(y[0])
return inner_function
if __name__ == "__main__":
inner = out_function() # inner = inner_function
inner()
inner()
#输出
variable test11
variable test22
variable test111
variable test222
- 字符串属于不可更改变量,需要改变时转变为列表元素即可。
- 使用nolocal关键字其实是标识了一个外层函数的变量,所以在内层函数中可以直接修改,因为此时的变量x直接映射到外层的变量。
4. 总结
闭包是一种常见的代码技巧,关于内外层变量值的修改问题,其实牵扯到的是内存分配的知识,可以参考代码执行时内存分配的相关知识,结合深浅拷贝去理解。