Python函数详解二闭包装饰器
闭包其实利用了函数嵌套的概念,一般函数在内部定义一个变量,在外部由于作用域的关系是调用不到的,而闭包是将变量包起来,不管在哪里都可以调用的到。
函数的嵌套定义:函数内定义了另外一个函数
#示例1name=Alicedefouter():definner():print(name)print(inner.__closure__)returninner
其中outer称为外部函数,inner称为内部函数。
对于一个函数,outer是其函数名,outer()为函数的调用,python中函数名可以用做函数的参数也可以作为函数的返回值。
那么什么是闭包呢?闭包满足的三个条件:
1.必须是嵌套函数;
2.内部函数必须引用外部函数中的变量
3.外部函数返回了内部函数或者外部函数调用了内部函数
查看是否为闭包:__closure__
#示例2defouter():name=Alicedefinner():print(name)print(inner.__closure__)#(cellat0xB4AEF3A0D8:strobjectat0xB4AEFF0,)returninner
可以试一下示例1的__closure__值,值是None,所以示例1并不是闭包,原因是内部函数没有引用外部函数的变量。
内部函数的调用f=outer()#调用外部函数,返回内部函数并存给ff()#调用内部函数
注意:
内函数不能直接被调用。
闭包中被内部函数引用的变量,不会因为外部函数结束而被释放掉,而是一直存在内存中,直到内部函数被调用结束。
闭包变量局部变量的作用域在函数内部,如果内部函数想修改外部函数的变量,有两种方法:
1.将变量声明为nonlocal,这表明变量不仅在函数内部生效,还在上一级函数中生效
defouter():name=Alicedefinner():nonlocalnamename=Hahaprint(name)returninnerf=outer()f()
2.把闭包变量改成可变类型数据进行修改,比如列表。
defouter():name=[Alice]definner():name=[Haha]print(name[0])returninnerf=outer()f()
注意:
1.nonlocal关键字只能用于嵌套函数中,并且外部函数中定义了相应的局部变量
2.外函数被调用一次返回了内函数,因此实际上闭包变量只有一份,以后每次调用内函数,都使用同一份闭包变量,一旦在内部函数修改了闭包变量,则这个闭包变量的值就已经修改了,不是最初的值了。
装饰器装饰器本质上是一个函数,使用了闭包的特性,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
现有函数:
defsleep_f():time.sleep(3)
如果要计算该函数的运行时间,代码如下
start_time=time.time()sleep_f()end_time=time.time()print("程序运行了{0:.4f}秒".format(end_time-start_time))
缺点:
1.调用sleep_f()依旧无法打印运行时间。
2.如果还有其他很多函数要显示运行时间,同样的代码得写很多遍。
解决方法:使用装饰器。
定义装饰器如下:deftimer(func):definner(*args,**kwargs):start_time=time.time()func(*args,**kwargs)end_time=time.time()print("程序运行了{0:.4f}秒".format(end_time-start_time))returninner
装饰器装饰函数的方法:函数的上一行加
装饰器名,其中,符号是装饰器的语法糖装饰器使用的两种方法:
装饰器不带参数#被装饰函数不带参数
timerdefsleep_f():time.sleep(3)#调用sleep_f,这时候就会打印运行时间了sleep_f()#被装饰函数带参数
timerdefadd(a,b):print(a+b)time.sleep(2)add(2,3)装饰器带参数timer装饰器打印了函数的运行时间,如果还想打印日志,即想要装饰器含参数,需要在timer的外层再装饰一层函数
defflog(name):deftimer(func):definner(*args,**kwargs):print("调用{}模块的{}函数".format(name,inner.__name__))start_time=time.time()func(*args,**kwargs)end_time=time.time()print("程序运行了{0:.4f}秒".format(end_time-start_time))returninnerreturntimerflog(module_a)defadd(a,b):print(a+b)time.sleep(2)#调用add(6,7)你点的每个好看,我都认真当成了喜欢预览时标签不可点收录于话题#个上一篇下一篇
转载请注明:http://www.sonphie.com/lcbx/14406.html