Python如何在类中定义装饰器
作者:AllardZhao
这篇文章主要介绍了Python如何在类中定义装饰器的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
如何在类中定义装饰器
实际案例
实现一个能将函数调用信息记录到日志的装饰器:
- 把每次函数的调用时间,执行时间,调用次数写入日志;
- 可以对被装饰函数分组,调用信息记录到不同日志;
- 动态修改参数,比如日志格式;
- 动态打开关闭日志输出功能。
解决方案
为了让装饰器在使用上更加灵活,我们把类的实例方法作为装饰器
此时在包裹函数中就可以持有实例对象,便于修改属性和拓展功能。
代码演示
# _*_ encoding:utf-8 _*_ import logging from time import localtime, time, strftime, sleep from random import choice class CallingInfo(object): # 通过name对为日志分组 def __init__(self, name): log = logging.getLogger(name) # 设置log的输出级别 log.setLevel(logging.INFO) # 输入到文件中 fh = logging.FileHandler(name + '.log') log.addHandler(fh) log.info('start'.center(50, '-')) # 将log变成实例属性 self.log = log # 定义日志的输出格式,函数名、开始时间,执行时间,调用次数 self.formatter = '%(func)s -> [%(time)s - ' \ '%(used)s - %(n_calls)s]' # 定义装饰器函数 def info(self, func): def wrapper(*args, **kwargs): wrapper.n_calls += 1 lt = localtime() start = time() res = func(*args, **kwargs) used = time() - start info = dict() info['func'] = func.__name__ info['time'] = strftime('%x %X', lt) info['used'] = used info['n_calls'] = wrapper.n_calls msg = self.formatter % info # 输出日志 self.log.info(msg) return res # 统计函数调用次数,函数属性类似于函数内的静态变量 wrapper.n_calls = 0 return wrapper # 动态修改formatter参数 def set_formatter(self, formatter): # 修改实例属性 self.formatter = formatter # 动态的打开和关闭日志输出,设置level输出级别 def turn_on(self): # INFO级别会输出日志 self.log.setLevel(logging.INFO) def turn_off(self): # 抬高日志输出级别就会关闭 self.log.setLevel(logging.WARN) # 将f和g输出到一个日志当中,h输出到另一个,需要创建2个实例 # 创建类的实例,使用实例的info方法去装饰函数 c_info1 = CallingInfo('my_log1') c_info2 = CallingInfo('my_log2') # 将c_info1日志修改为如下格式 c_info1.set_formatter('%(func)s -> [%(time)s - %(n_calls)s]') # 关闭c_info2的日志输出 c_info2.turn_off() @c_info1.info def f(): print('in f') @c_info1.info def g(): print('in g') @c_info2.info def h(): print('in h') # 测试代码, 循环50次 for _ in range(50): # 随机调用上面三个函数中的一个 choice([f, g, h])() # 随机秒数的睡眠 sleep(choice([0.5, 1, 1.5]))
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。