# -*- coding:utf-8 -*-
"""
实际案例:
实现一个能将函数调用信息记录到日志的装饰器:
1.把每次函数的调用时间,执行时间.调用次数写入日志.
2.可以对被装饰函数分组,调用信息记录到不同日志.
3.动态修改参数,比如日志格式.
4.动态打开关闭日志输出功能
解决方案:
为了让装饰器在使用上更加灵活,可以把类的实例方法作为装饰器,
此时在包裹函数中就可以持有实例对象,便于修改属性和拓展功能
"""
import logging
from time import localtime, time, strftime, sleep
from random import choice
class CallingInfo(object):
def __init__(self, name): # name决定日志输出到那个文件当中
log = logging.getLogger(name)
log.setLevel(logging.INFO) # 输出级别
fh = logging.FileHandler(name + '.log')
log.addHandler(fh)
log.info('Start'.center(50, '-')) # - 占位:-----------Start-----------
self.log = log
self.formatter = '%(func)s -> [%(time)s - %(used)s - %(ncalls)s]'
def info(self, func):
def wrapper(*args, **kwargs):
wrapper.ncalls += 1
lt = localtime()
start = time()
res = func(*args, **kwargs)
used = time() - start
info = {} # 构造字典
info['func'] = func.__name__
info['time'] = strftime('%x %X', lt)
info['used'] = used
info['ncalls'] = wrapper.ncalls
msg = self.formatter % info # 用字典格式化self.formatter得到输出信息
self.log.info(msg)
return res
wrapper.ncalls = 0 # 将调用次数作为函数的属性,比较方便调用
return wrapper
def setFormatter(self, formatter):
self.formatter = formatter
def turnOn(self):
"""降低级别"""
self.log.setLevel(logging.INFO)
def turnOff(self):
"""抬高级别"""
self.log.setLevel(logging.WARN)
cinfo1 = CallingInfo('mylog1')
cinfo2 = CallingInfo('mylog2')
cinfo1.setFormatter('%(func)s -> [%(time)s - %(ncalls)s]')
cinfo2.turnOff()
@cinfo1.info
def f():
print('in f')
@cinfo1.info
def g():
print('in g')
@cinfo2.info
def h():
print('in h')
for _ in range(50):
choice([f, g, h])() # choice 的使用
sleep(choice([0.5, 1, 1.5]))
9-5在类中定义装饰器
最新推荐文章于 2023-05-27 14:19:53 发布