【装饰器】让你的Python代码更Pythonic

有些时候我们需要打印方法的执行日志,最简单的方法就是在方法的开始写一个

logging,info("start")

在执行的最后写一个

logging,info("end")

但是这样未免显得代码有些臃肿,而且,不那么专业,

那么,类级别的装饰器就派上用场了。这个小伙伴可以帮你记录下每个方法的执行过程,让你知道你的程序在做什么,以及它是如何做到的。

当你使用这个装饰器时,它会跟着你的方法走,记录下每一步的日志。不仅如此,它还会在方法进入和退出时向你打个招呼,告诉你你的方法是如何被调用的。

下面是一个简单的例子,展示了如何使用类级别的装饰器来记录方法执行日志:

class PrintLog:
    def __init__(self, func):
        self.func = func
    
    def __call__(self, *args, **kwargs):
        with self:
            result = self.func(*args, **kwargs)
            return result
    
    def __enter__(self):
        print(f"Method {self.func.__name__} started. ")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"Method {self.func.__name__} finished. ")
        return False

@PrintLog
@staticmethod
def my_method(arg1, arg2):
    return result

使用 with 语句可以在装饰器中实现上下文管理器,使得在方法执行过程中发生的异常能够被捕获并正确处理。在进入方法之前,with 语句会自动调用 __enter__() 方法,在方法执行完毕后,也会自动调用 __exit__() 方法。

在上下文管理器中,__exit__() 方法的返回值可以控制是否将异常返回到上层调用者。如果 __exit__() 方法返回 True,则不会将异常返回到上层调用者,相当于告诉 Python 解释器异常已经被处理了,不需要继续抛出。如果返回 False,则会将异常返回到上层调用者。

__exit__() 方法中,可以通过 exc_type数来判断是否有异常发生。
可以参照下面这个处理方式。

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is not None:
            print(f"Method {self.func.__name__} failed: {exc_value} ")
        else:
            print(f"Method {self.func.__name__} finished. ")
        return False

我之前写的例子是用类级别的装饰器来处理静态方法的,因为静态方法不需要访问实例变量和实例方法,所以更适合用类级别的装饰器来装饰。如果需要装饰实例方法,可以使用 __get__ 方法来支持对实例方法的装饰。

    def __get__(self, instance, owner):
        return self.__class__(self.func.__get__(instance, owner))

OK,我把静态方法和实例方法的装饰器重新整理一下。

class PrintLog:
    def __init__(self, func):
        self.func = func
    
    def __call__(self, *args, **kwargs):
        with self:
            result = self.func(*args, **kwargs)
            return result
    
    def __get__(self, instance,cls):
        return self if instance is None else .__class__(self.func.__get__(instance, cls))


    def __enter__(self):
        print(f"Method {self.func.__name__} started. ")
        return self
    
    def __exit__(self, exc_type, exc_val, trace):

        if exc_type is not None:
            print(f"Method {self.func.__name__} failed: {exc_val}")    
        else:
            print(f"Method {self.func.__name__} finished. ")
        return False


这样的话,静态方法和实例方法都可以使用,
静态方法的执行顺序是: init call enter call exit
实例方法的执行顺序是: init get call enter call exit
※因为实例方法需要先得到一个实例。所以先执行get。

OK,希望都大家有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值