如果在一个内部函数里,对在外部作用域(非全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。定义在外部函数内的,担忧内部函数引用或者使用的变量称为自由变量,闭包在函数式编程中是一个重要的概念。
闭包将内部函数自己的代码和作用域以及外部函数的作用域结合起来,闭包的词法变量不余数全局名称空间域或者局部的——属于其他的名称空间。
python的namespace:
python通过namespace来检索变量/函数/方法,在python中有三种namespace
·local namespace
·build_in namespace
·global namespace
当函数/方法/变量发生重命令的时候,python按照如下的法则搜索
local > global > build_in
python创建闭包:
def foo(a):
def infoo(b):
print(a+b)
return infoo
x = foo(10)
x(20)
x = foo(10)
这里的10就是一个local_namespace,这个local_namespace并没有随着函数x()的运行结束而销毁,而是生命值得到了延续,延续到了内嵌函数infoo()中,
所以x(20)的结果为30,x可执行是因为foo()的返回值是另一个函数。
那么为什么a会被延续呢?我们看一下x的可用方法
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
其中有一个__closure__,可以下执行__closure__的结果
print(type(x.__closure__))
显示是一个元组,那么看一下这个元组的第一个元素
print(type(x.__closure__[0]))
是一个cell类,看一下这个类的值
print(x.__closure__[0].cell_contents)
10
证明了a被延续到了infoo()内
从这里可以看到闭包的原理,当内嵌函数引用了包含它的函数(enclosing function)中的变量后,这些变量会被保存在enclosing function的__closure__属性中,成为enclosing function本身的一部分;也就是说,这些变量的生命周期会和enclosing function一样。
在python中创建闭包的原则:
1,闭包函数必须内嵌函数
2,内嵌函数必须调用套嵌上一级函数的namespace
3,闭包韩式必须返回内嵌函数名
其实,python的装饰器就是闭包!