python 自定义装饰器实例详解
本文实例讲述了python自定义装饰器。分享给大家供大家参考,具体如下:
先看一个例子
defdeco(func): print("beforemyfunc()called.") func() print("aftermyfunc()called.") returnfunc @deco defmyfunc(): print("myfunc()called.") #myfunc=deco(myfunc)#与上面的@deco等价 myfunc() print("***********") myfunc()
会发现,输出为
beforemyfunc()called.
myfunc()called.
aftermyfunc()called.
myfunc()called.
***********
myfunc()called.
这就是说,装饰器里面的东西只调用了一次,为什么呢?
是因为,在myfunc()函数的定义前面加一句@deco,本质上完全等价于在出现defmyfunc()后,先将下面所有内容的首地址传递给func,然后紧接着加上一句myfunc=deco(myfunc)。执行这句话,表示func代表了本来定义的myfunc()的函数体,同时函数myfunc()的地址传递给deco()函数,即myfunc->func,这里就相当于myfunc的值与func的值完全相同了。然后执行装饰器里面的内容,最后返回给func,传递给myfunc。接下来在调用myfunc()的时候,打印输出“myfunc()called”。第二次调用myfunc()函数的时候,依然只打印输出“myfunc()called”。为什么第二次没有执行装饰器里面的内容呢?是因为,myfunc=deco(myfunc)这句话只执行了一次,而这句话,才是真正执行装饰器里面的内容的话。
上面的代码表示,装饰器相当于只对第一次调用他的函数进行了装饰,那么,怎么对每次调用的函数都装饰呢?接着看
defdeco(func): defwrapper(*args,**kwargs):#*args,**kwargs用于接收func的参数 print("beforemyfunc()called.") func(*args,**kwargs) print("aftermyfunc()called.") returnwrapper @deco defmyfunc(a,b): print(a+b) #myfunc=deco(myfunc)#与上面的@deco等价 myfunc(1,2) print("***********") myfunc(3,4)
该代码输出结果为
beforemyfunc()called.
3
aftermyfunc()called.
***********
beforemyfunc()called.
7
aftermyfunc()called.
我们说了,在myfunc()函数的定义前面加一句@deco,本质上完全等价于在出现def?myfunc()后,先将下面所有内容的首地址传递给func,然后紧接着加上一句myfunc=deco(myfunc)。执行myfunc(1,2)命令的时候,myfunc函数体的地址早已经传递给了deco()函数,返回的是wrapper。这是myfunc所代表的地址不再是原来的myfunc的地址,而是wrapper函数的地址。所以,以后凡是出现myfunc()的地方,都是在调用wrapper()函数。即myfunc(1,2)就是wrapper(1,2),所以每次调用myfunc()时候,装饰器里面的内容都会被执行了。而wrapper()函数体里面的func,就代表了原来myfunc()的函数体。
怎么进一步理解“在出现def?myfunc()后,先将下面所有内容的首地址传递给func”这句话呢?看:
defdeco(func): defwrapper(*args,**kwargs):#*args,**kwargs用于接收func的参数 print("wrapper的地址:",wrapper) func(*args,**kwargs) print("func的地址:",func) returnwrapper @deco defmyfunc(a,b): print("myfunc的地址:",myfunc) print(a+b) #myfunc=deco(myfunc)#与上面的@deco等价 myfunc(1,2) print("***********") print("修改后myfunc的地址:",myfunc)
运行结果:
wrapper的地址:
.wrapperat0x0000023AA9FF58C8>
myfunc的地址:.wrapperat0x0000023AA9FF58C8>
3
func的地址:
***********
修改后myfunc的地址:.wrapperat0x0000023AA9FF58C8>
程序执行到myfunc(1,2)的时候,本质上是在执行wrapper(1,2),于是先输出wrapper的地址,再执行func()函数。执行func()函数的时候,输出myfunc()的地址,(可见,此时myfunc的值与wrapper的是相等),再打印3。当输出func()函数的地址,可见func()函数的地址与myfunc()函数的地址不一样了!!!!这就是说,原来定义的myfunc()函数的函数体,已经属于func了,而不属于myfunc了!!
进一步见证奇迹!!
defdeco(func): defwrapper(*args,**kwargs):#*args,**kwargs用于接收func的参数 pass returnwrapper @deco defmyfunc(a,b): print(a+b) myfunc(1,2)
该代码没有任何输出。那是因为,执行myfunc(1,2)的时候,本质上是执行wrapper(1,2)。而wrapper(1,2)又不干任何事情,所以没有输出。至于print(a+b)这句话,他的地址已经属于func了。
带参数的装饰器,可以参见其他文章
更多关于Python相关内容可查看本站专题:《Python数据结构与算法教程》、《PythonSocket编程技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python入门与进阶经典教程》
希望本文所述对大家Python程序设计有所帮助。