在学习装饰器的过程中,我们必须先越过一个坎,那就是闭包函数。
关于闭包函数,有三个可以参考的定义:
闭包函数的定义:
第一:定义在内部的函数包含对外部作用域(而非全局作用域)变量的引用,该内部函数就称为闭包函数。
第二:简单的说,闭包就是根据不同的配置信息得到不同的结果。
第三:简单的说,内部函数可以使用外部函数变量的行为,叫做闭包。
闭包函数的两个特点:
第一:闭包函数一定是在一个函数的内部进行定义的;
第二:定义在内部的函数必须包含对外部作用域变量的引用。
只要满足上面两个条件,就称为闭包函数。
下面我们进行闭包函数的判断:
示例1:
def f1(): def f2(): x = 1 print(x)
在上面的例子中,f2这个函数虽然是在一个函数内部进行定义的,但是并没有包含对外部作用域变量的引入,所以f2这个函数并不是闭包函数。
示例2:
x = 1 def f1(): def f2(): print(x)
在上面的例子中,f2这个函数虽然是在一个函数内部进行定义的,但是并没有包含对外部作用域变量的引入,因为x=1是一个全局作用域变量,所以2这个函数并不是闭包函数。
闭包函数实例场景:惰性计算(延迟计算)将某种状态先保存起来,什么时候用就用。
示例1:
#!/usr/bin/python # -*- coding:utf-8 -*- def make_adder(m): def adder(n): return m + n return adder p = make_adder(30) q = make_adder(40) #本是相同的函数adder,但是由于配置信息的不同,导致运行结果并不相同 print(p.__name__,q.__name__) print(p(20)) print(q(20)) #查看相应的配置信息:即闭包函数引用外部作用域的变量 print(p.__closure__[0].cell_contents) print(q.__closure__[0].cell_contents)
在上面的例子中,我们不难发现,无论是make_adder(30)还是make_adder(40)返回的都是adder这个函数对象,但是由于配置信息的不同,导致运行结果并不相同。
还是那句话:在python中,函数是第一类对象,函数的名字相当于指针变量,里面存放的是对应函数体的地址。
示例2:
#!/usr/bin/python # -*- coding:utf-8 -*- def foo(m,n): def bar(a): return m + n + a return bar fun = foo(10,50) print('指针变量fun的数值是:%s'%fun) print(fun.__name__,fun.__closure__) for item in fun.__closure__: print(item.cell_contents) print(fun(20))
相应debug视图:
OK,闭包函数就讲到这里。