python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python在类中定义装饰器

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]))

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文