装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
1 简单的装饰器
def use_logging(func):
def wrapper():
logging.warn("%s is running" % func.__name__)
return func() # 把 foo 当做参数传递进来时,执行func()就相当于执行foo()
return wrapper
def foo():
print('i am foo')
foo = use_logging(foo) # 因为装饰器 use_logging(foo) 返回的时函数对象 wrapper,这条语句相当于 foo = wrapper
foo() # 执行foo()就相当于执行 wrapper()
1.1语法糖:@ 符号就是装饰器的语法糖
def use_logging(func):
def wrapper():
logging.warn("%s is running" % func.__name__)
return func()
return wrapper
@use_logging
def foo():
print("i am foo")
foo()
1.2 *args、**kwargs
当装饰器不知道 foo 到底有多少个参数时,我们可以用 *args 来代替:
一个参数时:
def wrapper(name): logging.warn("%s is running" % func.__name__) return func(name) return wrapper
def foo(name): print("i am %s" % name)
多个参数时:
def wrapper(*args): logging.warn("%s is running" % func.__name__) return func(*args) return wrapper
包含关键字参数时:
def foo(name, age=None, height=None): print("I am %s, age %s, height %s" % (name, age, height))
可以这样写:
def wrapper(*args, **kwargs): # args是一个数组,kwargs一个字典 logging.warn("%s is running" % func.__name__) return func(*args, **kwargs) return wrapper