也写过一些装饰器,但记忆不够深刻,这次系统总结一下以备忘。
功能
给一个函数增加额外的功能或操作
实现
一个装饰器就是一个函数或类,它接受一个函数作为参数并返回一个新的函数,返回的函数跟被装饰的函数接收相同的参数
@语法糖
@d
def f ():
pass
上面的下面这样是等价的。
def f ():
pass
f = d(f)
在过往的工作和学习中,遇到的使用装饰器的场景有以下几种:
- 权限校验,比如某个接口需要用户是登录的状态才能访问
- 日志记录,记录接口的调用和执行信息,参数、执行时间等
- 异常处理,例如sentry收集异常
简单装饰器
1 | def deco1(f): |
装饰器没有参数,被装饰的函数可以接收参数
带参数的装饰器
1 | def deco2(flag): |
装饰器也带参数, 注意嵌套了两层。
装饰器的副作用
你写了一个装饰器作用在某个函数上,但是这个函数的重要的元信息比如名字、文档字符串、注解和参数签名都丢失了,应该使用 functools 库中的 @wraps 装饰器来注解底层包装函数, wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器里面的函数中,这使得装饰器里面的函数也有和原函数一样的元信息了.
1 | from functools import wraps |
多个装饰器
1 | @a |
等价于 f = a(b(c(f)))), 先调用最里层的,然后从里到外。
类装饰器
依靠call方法实现
1 | class Foo(object): |
def dec_a(f):
print(“dec a”)
def wrapper_a(args, **kw):
print(“wrap a”)
return f(args, **kw)
return wrapper_a
def dec_b(f):
print(“dec b”)
def wrapper_b(args, **kw):
print(“wrap b”)
return f(args, **kw)
return wrapper_b
打印出来的结果
@dec_b
@dec_a
def f():
print(“hello”)
f = dec_b(dec_a(f))
if name == “main“:
f()
f()
参考: