zoukankan      html  css  js  c++  java
  • 如何在类中定义装饰器?

    需求:
    实现一个能将调用信息记录到日志的装饰器:
    1、把每次函数的调用时间,执行时间,调用次数写入日志
    2、可以对被装饰的函数分组,调用信息记录到不同的日志
    3、动态修改参数,比如日志格式
    4、动态打开关闭日志输出功能

    @call_info(arg1,arg2,arg3...)
    def func(a,b):
    ...

    思路:
    为了让装饰器在使用上更加灵活,可以把类的实例方法作为装饰器,此时在包裹函数中就可以持有实例对象,便于修改属性和拓展功能

    代码:

    import time
    import logging
    
    DEFAULT_FORMAT = '%(func_name)s -> %(call_time)s	%(used_time)s	%(call_n)s'
    
    class CallInfo:
        def __init__(self,log_path,format_=DEFAULT_FORMAT,on_off=True):
            self.log = logging.getLogger(log_path)
            self.log.addHandler(logging.FileHandler(log_path))
            self.log.setLevel(logging.INFO)
            self.format = format_
            self.is_on = on_off
    
        # 装饰器方法
        def info(self,func):
            _call_n = 0
            def wrap(*args,**kwargs):
                func_name = func.__name__
                call_time = time.strftime('%x %X',time.localtime())
                t0 = time.time()
                res = func(*args,**kwargs)
                used_time = time.time() - t0
                nonlocal _call_n
                _call_n += 1
                call_n = _call_n
                if self.is_on:
                    self.log.info(self.format % locals() )
                return res
            return wrap
    
        def set_format(self,format_):
            self.format = format_
    
        def turn_on_off(self,on_off):
            self.is_on = on_off
    
    # 测试代码
    import random
    
    ci1 = CallInfo('mylog1.log')
    ci2 = CallInfo('mylog2.log')
    @ci1.info
    def f():
        sleep_time = random.randint(0,6) * 0.1
        time.sleep(sleep_time)
    
    @ci1.info
    def g():
        sleep_time = random.randint(0,8) * 0.1
        time.sleep(sleep_time)
    
    @ci2.info
    def h():
        sleep_time = random.randint(0,7) * 0.1
        time.sleep(sleep_time)
    
    for _ in range(30):
        random.choice([f,g,h])()
    
    ci1.set_format('%(func_name)s -> %(call_time)s	%(call_n)s')
    for _ in range(30):
        random.choice([f,g])()
    
    ========================================================
    
    >>> def f():
    ...     x = 1
    ...     y = [1,2,3]
    ...     z = 'abc'
    ...     print(locals())
    ...     
    >>> f()
    {'x': 1, 'y': [1, 2, 3], 'z': 'abc'}
    
    
  • 相关阅读:
    ACM算法
    过度拟合的问题
    多类分类:一对多
    先进的优化
    简化成本函数和梯度下降
    对数回归的成本函数
    决策边界
    假设表示
    分类
    hdu1574 I Hate It (线段树,查询区间最大值)
  • 原文地址:https://www.cnblogs.com/Richardo-M-Q/p/13959479.html
Copyright © 2011-2022 走看看