简介
在Python以及很多编程语言中,都存在嵌套函数的概念,就是可以在一个函数内部定义函数,这个函数叫外部函数,内部定义的函数叫内部函数,闭包就是一个特殊的内部函数,它必须满足三个条件:
- 一个内部函数
- 外部函数的返回值是这个内部函数
- 引用了外部函数的参数或局部变量
下面就是一个典型的闭包的例子:
>>> def outer_fun():
... a = 1
... def inner_fun(b):
... c = a + b
... return c
... return inner_fun
>>> func1 = outer_fun()
>>> func1
<function outer_fun.<locals>.inner_fun at 0x104fe99d8>
注意在内部函数中尽量不要引用会发生变化的外部变量,否则可能会得到不符合预期的结果:
>>> def outer_fun():
... a = 1
... def inner_fun(b):
... c = a + b
... return c
... a += 1
... return inner_fun
>>>
>>> func1 = outer_fun()
>>> func1(1) //预期是2,但是由于闭包返回时并未真正执行,而引用的a的值在后面加了1,所有在真正执行的时候a的值已经是2,结果就是3
3
原理
基于我们对作用域的理解,outer_fun函数中的局部变量a应该在函数返回后失效,但是因为返回的内部函数inner_fun引用了它,所以它并没有失效,而是存在了返回的函数的__closure__属性中:
>>> func1.__closure__
(<cell at 0x1046e0dc8: int object at 0x1009e1980>,)
>>> func1__closure__[0]
<cell at 0x1046e0dc8: int object at 0x1009e1980>
>>>> func1.__closure__[0].cell_contents
1
>>>> type(func1.__closure__[0].cell_contents)
<class 'int'>
由上面例子可见,闭包的__closure__属性是个tuple,它是一个对应了所有闭包引用外部函数的参数集合,每个参数对应一个cell对象,这个cell对象的cell_contents属性对应参数的值。
用处
闭包的实现和理解都稍微有点难度,那么我们为什么费劲实现它呢:
1. 它是装饰器(Decorator)实现的基础,装饰器的作用毋庸置疑。
2. 它其实是一种简化版的面向对象的实现方式,在面向对象里面,对象包含自己的属性和方法,而一个闭包也可以看做是一个对象,它有自己的一些属性和仅有的一个方法。
当然还有其他的好处,比如避免了使用全局变量,等等不一一列举。