@chengweihuang
2019-04-19T01:55:17.000000Z
字数 1182
阅读 456
闭包
def fun_out(a):def fun_in(b):return a + breturn fun_infun1 = fun_out(1)
其中fun1函数是一个闭包,它携带着fun_out中定义的a变量,值为1。运行程序的效果是这样的.
>>> fun1 = fun_out(1)>>> fun1(3)4>>> fun1(6)7>>> fun5 = fun_out(5)>>> fun5(3)8>>> fun5(6)11
fun1和fun5两个函数的定义相同,只是携带的自由变量不同,便成为了两个函数。由此闭包可以作为函数工厂,生产出功能类似,但是会有细微差别的函数。(与类相似)
为了能够更深入地理解闭包,我们需要对变量作用域进行说明,以下面代码为例 这里fun_in函数是一个闭包吗?
d = 3def fun_out():a = 1def fun_in(c):b = 2return breturn fun_in
在fun_in函数中调用一个变量,搜索路径如下
先在fun_in函数定义的局部空间中开始搜索,这部分变量包括上面的b c
如果在局部空间中找不到,则在全局空间中搜索,即d所在位置
如果还是找不到会去找python内置变量
如果还是找不到则抛出异常
这里有一个问题,为什么没有提到变量a所在空间?
因为按常理来说,函数fun_out运行结束后,这个函数中定义的变量是不可以被其他函数直接引用的,也就是说这里的变量只能函数fun_out它自己用。
但是因为闭包的特性,如果在fun_in函数中引用了a变量(上面代码中没有),则fun_out运行return fun_in时,会将a变量绑定到fun_in函数上返回,因此此时(是闭包时)fun_in函数是可以搜索到变量a的
这就导致了一个现象,即如果fun_in函数是一个闭包,则在搜索变量时,实际上相当于是按照这样的顺序:局部->非局部非全局(a位置)->全局->内置->抛出异常
def fun_out(a):def fun_in(b):return a + breturn fun_infun1 = fun_out(99)print(fun1.__closure__) # 自由变量#<cell at 0x00000015BBADC5B8: int object at 0x00000000725C7850>#print(fun1.__closure__[0].cell_contents)# 如果没有引用 a 则打印None
class Add:def __init__(self, b):self.b = bdef __call__(self, a):return a + self.badd1 = Add(1)print(add1(3))add5 = Add(5)print(add5(3))#__call__是一个很神奇的特性,只要某个类型中有__call__方法,,我们可以把这个类型的对象当作函数来使用。