python类装饰器

class logger(object):
    logs = {}
    def __init__(self, func):
        self.func = func
        if func.__name__ not in self.logs:
            self.logs[func.__name__] = func

    def __call__(self, *args, **kwargs):
        print("[INFO]: the function {func}() is running..."\
            .format(func=self.func.__name__))
        return self.func(*args, **kwargs)

@logger
def say(something):
    print("say {}!".format(something))


@logger
def say1(something):
    print("say1 {}!".format(something))
    
say("hello")

say1("hello")

当使用@logger装饰器时,Python会执行say = logger(say),这会创建一个logger类的实例(即logger_instance),并将原函数say作为参数传递给__init__方法。这个实例会被赋值给say,因此后续调用say(“hello”)实际上是在调用这个

在Python中,当使用类作为装饰器时(如@logger),其执行流程遵循装饰器的底层机制和类的特殊方法调用规则。以下是关键原因分析:

1、 ​​@logger时执行__init__的原因​​
当使用@logger语法时,Python会​​立即执行装饰器类的初始化​​,相当于:

say = logger(say)  # 触发__init__

当执行@logger时,相当于:

say = logger(say) # 创建logger类的实例,并赋值给say
logger(say)会调用logger.__init__,生成一个logger类的实例(即logger_instance)。
此时say不再是原函数,而是logger类的实例。

​​装饰器本质​​:装饰器语法糖会将目标函数(如say)作为参数传递给装饰器类,此时会调用类的__init__方法。
​​初始化作用​​:__init__用于保存被装饰的函数(self.func = func)或执行其他初始化逻辑(如注册函数到logs字典)。
2、​​say()时调用__call__的原因​​
当调用被装饰的函数(如say(“hello”))时,实际调用的是装饰器类的实例,而类实例的调用行为由__call__方法定义:

​​可调用对象​​:实现了__call__的类实例可以像函数一样被调用。
​​执行流程​​:

say("hello")  # 等价于 logger_instance.__call__("hello")

__call__方法会在每次调用时执行,包裹原函数(如打印日志、执行self.func(*args, ​**​kwargs))
在Python中,如果一个类实现了__call__方法,它的实例就可以像函数一样被调用。
当执行say(“hello”)时,Python会隐式调用logger_instance.__call__(“hello”),这是__call__方法的特性。

# 有参数的类装饰器    
if 0:
    class logger(object):
        def __init__(self, level='INFO'):
            self.level = level

        def __call__(self, func): # 接受函数
            def wrapper(*args, **kwargs):
                print("[{level}]: the function {func}() is running..."\
                    .format(level=self.level, func=func.__name__))
                func(*args, **kwargs)
            return wrapper  #返回函数

    @logger(level='WARNING') # 构造传递参数
    def say(something):
        print("say {}!".format(something))

    say("hello")
    
if 1:    
    # 其实相当于下面这种写法
    def logger(level): # 外层相当于__init__
        def decorator(func): # 相当于__call__
            def wrapper(*args, **kwargs): 
                return func(*args, **kwargs)
                
            return wrapper
        
        return decorator
    
    @logger(level='WARNING') # 构造传递参数
    def say(something):
        print("say {}!".format(something))

    say("hello")

    
if 1:
    # 借助partial实现可以达到上面同样的效果
    import time
    import functools

    class DelayFunc:
        def __init__(self,  level, func):
            self.level = level
            self.func = func

        def __call__(self, *args, **kwargs):
            return self.func(*args, **kwargs)

    def delay(level):
        # 此处为了避免定义额外函数,
        # 直接使用 functools.partial 帮助构造 DelayFunc 实例,可以传递参数并避免__call__中额外定义函数
        return functools.partial(DelayFunc, level)
    
    @delay(level='WARNING') # 构造传递参数
    def say(something):
        print("say {}!".format(something))

    say("hello")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值