Python的闭包Closure

简介

在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. 它其实是一种简化版的面向对象的实现方式,在面向对象里面,对象包含自己的属性和方法,而一个闭包也可以看做是一个对象,它有自己的一些属性和仅有的一个方法。

当然还有其他的好处,比如避免了使用全局变量,等等不一一列举。

猜你喜欢

转载自blog.csdn.net/zhanghedong526/article/details/80219639