装饰器的本质
装饰器(不带参数的装饰器)从实现上看,就是一个“输入和输出都是函数对象”的函数;
带参数的装饰器实际上就是一个返回普通装饰器的函数(可以接受任意参数);
装饰器语法实际上就是以下两种调用形式的语法糖:
# 不带参数 func = decorator(func) # 带参数 func = decorator(*args)(func)类装饰器同理,就是一个“输入和输出都是类对象”的函数,也是类似的语法糖;
# 不带参数 clas = decorator(clas) # 带参数 clas = decorator(*args)(clas)装饰器类:具有装饰器功能的类,通过重载
__call__实现;
示例 1:装饰器(不带参数)
示例 1:装饰器(不带参数)定义装饰器
调用装饰器
等价行为
示例 2:带参数的装饰器
示例 2:带参数的装饰器定义装饰器
调用装饰器
等价行为
示例 3:functools.wraps 的作用
示例 3:functools.wraps 的作用在示例 2 中,打印
func.__name__的结果是wrapper; 这是因为经过装饰器后,func实际上已经指向了另一个函数;这时可以通过
functools.wraps装饰器保留原函数的相关属性,用法如下:functools.wraps本身也是一个带参数的装饰器;
示例 4:类装饰器
示例 4:类装饰器类装饰器就是一个“输入和输出都是类对象”的函数;
定义一个类装饰器:给装饰的类添加一个
printf函数调用装饰器
等价行为
示例 5:装饰器类(不带参数)
示例 5:装饰器类(不带参数)装饰器类:具有装饰器功能的类,通过重载
__call__实现;需要注意的是,该场景下不能使用
functools.wraps,而应该使用functools.update_wrapper,详见示例;
定义装饰器类
调用装饰器类
等价行为
示例 6:带参数的装饰器类
示例 6:带参数的装饰器类定义装饰器类
调用装饰器类
等价行为
Last updated