python装饰器原理与用法深入详解
本文实例讲述了python装饰器原理与用法。分享给大家供大家参考,具体如下:
你会Python嘛?
我会!
那你给我讲下Python装饰器吧!
Python装饰器啊?我没用过哎
以上是我一个哥们面试时候发生的真实对白。
----------------------------------------------分割线------------------------------------------------------------------------------
简言之,python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。
一般而言,我们要想拓展原来函数代码,最直接的办法就是侵入代码里面修改,例如:
importtime
deffunc():
print("hello")
time.sleep(1)
print("world")
这是我们最原始的的一个函数,然后我们试图记录下这个函数执行的总时间,那最简单的做法就是:
#原始侵入,篡改原函数
importtime
deffunc():
startTime=time.time()
print("hello")
time.sleep(1)
print("world")
endTime=time.time()
msecs=(endTime-startTime)*1000
print("timeis%dms"%msecs)
但是如果你的Boss在公司里面和你说:“小祁,这段代码是我们公司的核心代码,你不能直接去改我们的核心代码。”那该怎么办呢,我们仿照装饰器先自己试着写一下:
#避免直接侵入原函数修改,但是生效需要再次执行函数
importtime
defdeco(func):
startTime=time.time()
func()
endTime=time.time()
msecs=(endTime-startTime)*1000
print("timeis%dms"%msecs)
deffunc():
print("hello")
time.sleep(1)
print("world")
if__name__=='__main__':
f=func
deco(f)#只有把func()或者f()作为参数执行,新加入功能才会生效
print("f.__name__is",f.__name__)#f的name就是func
这里我们定义了一个函数deco,它的参数是一个函数,然后给这个函数嵌入了计时功能。然后你可以拍着胸脯对老板说,看吧,不用动你原来的代码,我照样拓展了它的函数功能。
然后你的老板有对你说:“小祁,我们公司核心代码区域有一千万个func()函数,从func01()到func1kw(),按你的方案,想要拓展这一千万个函数功能,就是要执行一千万次deco()函数,这可不行呀,我心疼我的机器。”
好了,你终于受够你老板了,准备辞职了,然后你无意间听到了装饰器这个神器,突然发现能满足你闫博士的要求了。
我们先实现一个最简陋的装饰器,不使用任何语法糖和高级语法,看看装饰器最原始的面貌:
#既不需要侵入,也不需要函数重复执行
importtime
defdeco(func):
defwrapper():
startTime=time.time()
func()
endTime=time.time()
msecs=(endTime-startTime)*1000
print("timeis%dms"%msecs)
returnwrapper
@deco
deffunc():
print("hello")
time.sleep(1)
print("world")
if__name__=='__main__':
f=func#这里f被赋值为func,执行f()就是执行func()
f()
这里的deco函数就是最原始的装饰器,它的参数是一个函数,然后返回值也是一个函数。其中作为参数的这个函数func()就在返回函数wrapper()的内部执行。然后在函数func()前面加上@deco,func()函数就相当于被注入了计时功能,现在只要调用func(),它就已经变身为“新的功能更多”的函数了。
所以这里装饰器就像一个注入符号:有了它,拓展了原来函数的功能既不需要侵入函数内更改代码,也不需要重复执行原函数。
#带有参数的装饰器
importtime
defdeco(func):
defwrapper(a,b):
startTime=time.time()
func(a,b)
endTime=time.time()
msecs=(endTime-startTime)*1000
print("timeis%dms"%msecs)
returnwrapper
@deco
deffunc(a,b):
print("hello,hereisafuncforadd:")
time.sleep(1)
print("resultis%d"%(a+b))
if__name__=='__main__':
f=func
f(3,4)
#func()
然后你满足了Boss的要求后,Boss又说:“小祁,我让你拓展的函数好多可是有参数的呀,有的参数还是个数不定的那种,你的装饰器搞的定不?”然后你嘿嘿一笑,深藏功与名!
#带有不定参数的装饰器
importtime
defdeco(func):
defwrapper(*args,**kwargs):
startTime=time.time()
func(*args,**kwargs)
endTime=time.time()
msecs=(endTime-startTime)*1000
print("timeis%dms"%msecs)
returnwrapper
@deco
deffunc(a,b):
print("hello,hereisafuncforadd:")
time.sleep(1)
print("resultis%d"%(a+b))
@deco
deffunc2(a,b,c):
print("hello,hereisafuncforadd:")
time.sleep(1)
print("resultis%d"%(a+b+c))
if__name__=='__main__':
f=func
func2(3,4,5)
f(3,4)
#func()
最后,你的老板说:“可以的,小祁,我这里一个函数需要加入很多功能,一个装饰器怕是搞不定,装饰器能支持多个嘛"
最后你就把这段代码丢给了他:
#多个装饰器
importtime
defdeco01(func):
defwrapper(*args,**kwargs):
print("thisisdeco01")
startTime=time.time()
func(*args,**kwargs)
endTime=time.time()
msecs=(endTime-startTime)*1000
print("timeis%dms"%msecs)
print("deco01endhere")
returnwrapper
defdeco02(func):
defwrapper(*args,**kwargs):
print("thisisdeco02")
func(*args,**kwargs)
print("deco02endhere")
returnwrapper
@deco01
@deco02
deffunc(a,b):
print("hello,hereisafuncforadd:")
time.sleep(1)
print("resultis%d"%(a+b))
if__name__=='__main__':
f=func
f(3,4)
#func()
'''
thisisdeco01
thisisdeco02
hello,hereisafuncforadd:
resultis7
deco02endhere
timeis1003ms
deco01endhere
'''
多个装饰器执行的顺序就是从最后一个装饰器开始,执行到第一个装饰器,再执行函数本身。
盗用评论里面一位童鞋的例子:
defdec1(func):
print("1111")
defone():
print("2222")
func()
print("3333")
returnone
defdec2(func):
print("aaaa")
deftwo():
print("bbbb")
func()
print("cccc")
returntwo
@dec1
@dec2
deftest():
print("testtest")
test()
输出:
aaaa
1111
2222
bbbb
testtest
cccc
3333
装饰器的外函数和内函数之间的语句是没有装饰到目标函数上的,而是在装载装饰器时的附加操作。
17~20行是装载装饰器的过程,相当于执行了test=dect1(dect2(test)),此时先执行dect2(test),结果是输出aaaa、将func指向函数test、并返回函数two,然后执行dect1(two),结果是输出1111、将func指向函数two、并返回函数one,然后进行赋值。
用函数替代了函数名test。22行则是实际调用被装载的函数,这时实际上执行的是函数one,运行到func()时执行函数two,再运行到func()时执行未修饰的函数test。
更多关于Python相关内容感兴趣的读者可查看本站专题:《Python面向对象程序设计入门与进阶教程》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python编码操作技巧总结》及《Python入门与进阶经典教程》
希望本文所述对大家Python程序设计有所帮助。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。