Python装饰器是Python的一个重要部分,作用是修改其他函数,并且不会影响调用方式,根据我个人的理解,梳理一下思路,帮助理解装饰器。
首先,Python中万物皆对象,对于函数,可以直接赋值:
def hi(): return 'hi' print(hi()) #output: ‘hi’
#可以直接把函数赋值给变量 hello = hi print(hello()) #output: 'hi'
#并且删除原函数后,依然可以调用hello del hi print(hello()) #output: 'hi'
函数内部也可以定义函数:
def hi(): def hello(): return 'hello' return hello()
print(hi())
#output: 'hello'
函数还可以作为参数或者返回值:
def hi(): def hello(): return 'hello' return hello #将hello赋值给Greetings Greetings = hi() print(Greetings()) #或者 print(hi()()) #output: 'hello'
def hi(): return 'hi' def hello(func_name): return func_name() #将hi作为hello的参数 print(hello(hi)) #output: 'hi'
有了上面的理解,可以作出下面的写法:
def hi(): print('hi') def decorator(func_name): def wrapTheFunction(): print('before hi') func_name() print('after hi') return wrapTheFunction hi = decorator(hi) hi()
#outputs: before hi # hi # after hi
所以,这样其实就得到了一个装饰器,装饰器做的事情就是封装一个函数,添加一些动作然后再返回来。
然后‘@’符号,其实就是一种方便的用法,方便的生成一个被装饰的函数,有了@,就不用自己去hi = decorator(hi)这样赋值了。
上面的写法虽然表面上看已经实现了我们改变hi这个函数的功能的需要,但是由于hi = decorator(hi)这个赋值,其实hi指向的是wrapTheFunction函数,通过打印hi.__name__就可以发现,
出来的结果是#wrapTheFunction,专业的说法是它重写了我们函数的名字和注释文档(docstring)。所以要实现最终的目的,还需要一个系统提供的函数functools.wraps。
(@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。)
更改后的写法如下:
from functools import wraps def decorator(func_name): @wraps(func_name) def wrapTheFunction(): print('before hi') func_name() print('after hi') return wrapTheFunction @decorator def hi(): print('hi') print(hi.__name__) #output:hi
至此,就是完全体的装饰器了。终于明白了。
装饰器最大的作用,就是在不影响原函数的调用方式上,不需要修改原函数的代码,而对原函数的功能进行扩充,当然,装饰器本质上还是函数,所以它同时有函数的优点,即可复用性,
所以写出一个装饰器,不仅仅可以增加一个函数的功能,以后其他函数也有类型需求的时候直接拿过来就就行了,这就是相比直接修改原函数的优势。