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]))总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
