Python如何在类中定义装饰器

 更新时间:2024年02月09日 09:58:54   作者: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]))

总结

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

相关文章

  • 使用Python实现MP3格式转化

    使用Python实现MP3格式转化

    这篇文章主要为大家详细介绍了如何使用Python实现MP3格式转化为wav,flac和ogg等,文中的示例代码讲解详细,有需要的小伙伴可以参考一下
    2025-01-01
  • Python中if语句的基本格式实例代码

    Python中if语句的基本格式实例代码

    在Python中,if语句用于根据条件执行不同的代码块。本文详细介绍了Python中if语句的基本格式使用方法及实例代码,有需要的同学可以参考阅读
    2023-05-05
  • Python实现一个转存纯真IP数据库的脚本分享

    Python实现一个转存纯真IP数据库的脚本分享

    工作中我们常需要使用纯真IP数据库内的数据做分析,下面这篇文章主要给大家介绍了利用Python如何实现一个转存纯真IP数据库的相关资料,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-05-05
  • python str与repr的区别

    python str与repr的区别

    repr() 输出对 Python比较友好,而str()的输出对用户比较友好。虽然如此,很多情况下这三者的输出仍然都是完全一样的
    2013-03-03
  • Python实现的在特定目录下导入模块功能分析

    Python实现的在特定目录下导入模块功能分析

    这篇文章主要介绍了Python实现的在特定目录下导入模块功能,结合实例形式分析了Python基于系统函数及import语句实现模块导入的相关操作技巧,需要的朋友可以参考下
    2019-02-02
  • Python跨文件实现字符串填充的三种实现方法

    Python跨文件实现字符串填充的三种实现方法

    本文主要介绍了Python跨文件实现字符串填充的三种实现方法,包括format方法、%格式化操作符和eval函数结合f-string,具有一定的参考价值,感兴趣的可以了解一下
    2024-12-12
  • Python面向对象之类的定义与继承用法示例

    Python面向对象之类的定义与继承用法示例

    这篇文章主要介绍了Python面向对象之类的定义与继承用法,结合实例形式分析了Python类的定义、实例化、继承等基本操作技巧,需要的朋友可以参考下
    2019-01-01
  • python矩阵的基本运算及各种操作

    python矩阵的基本运算及各种操作

    python的numpy库提供矩阵运算的功能,因此我们在需要矩阵运算的时候,需要导入numpy的包,下面这篇文章主要给大家介绍了关于python矩阵的基本运算及各种操作的相关资料,需要的朋友可以参考下
    2022-11-11
  • colab中修改python版本的全过程

    colab中修改python版本的全过程

    日 对于没有服务器的研究生来说,Colab无疑是性价比最高的GPU选择,下面这篇文章主要给大家介绍了关于如何利用colab修改python版本的相关资料,需要的朋友可以参考下
    2022-04-04
  • Flask核心机制之上下文源码剖析

    Flask核心机制之上下文源码剖析

    这篇文章主要介绍了Flask核心机制之上下文源码剖析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12

最新评论