Python 装饰器装饰类中的方法
目前在中文网上能搜索到的绝大部分关于装饰器的教程,都在讲如何装饰一个普通的函数,或者把类方法当做普通函数装饰。但如果要在装饰器里面运行你装饰的这个方法所在的类中的其他方法和属性,应该如何操作?
以捕获一个方法的异常为例来进行说明。我们写一个类Test, 它的结构如下:
class Test(object): def restore(self): print('恢复现场环境') def read_value(self): print('从某个地方读取数据')
在类中有一个方法read_value()
,这个方法在多个地方被调用。由于某些原因,方法read_value
有可能随机抛出Exception导致程序崩溃。所以需要对整个方法做try ... except
处理。最丑陋的做法如下面的代码所示:
class Test(object): def restore(self): print('恢复现场环境') def read_value(self): try: print('从某个地方读取数据') # 这里可能会发生异常 except Exception as e: print(f'发生异常: {e}') print('恢复环境...') self.restore()
这样写虽然可以解决问题,但是代码不Pythonic。
使用装饰器来解决这个问题,装饰器函数应该写在类里面还是类外面呢?答案是,写在类外面。那么既然写在类外面,如何调用这个类的其他方法呢?
首先写出一个最常见的处理异常的装饰器:
def catch_exception(origin_func): def wrapper(*args, **kwargs): try: u = origin_func(*args, **kwargs) return u except Exception: return '' return wrapper class Test(object): def restore(self): print('恢复现场环境') @catch_exception def read_value(self): print('从某个地方读取数据')
这种写法,确实可以捕获到origin_func()
的异常,但是如果在发生异常的时候,怎么需要调用类里面的restore
方法?答案是给wrapper增加一个参数:self
.
代码变为如下形式:
def catch_exception(origin_func): def wrapper(self, *args, **kwargs): try: u = origin_func(self, *args, **kwargs) return u except Exception: self.revive() #不用顾虑,直接调用原来的类的方法 return '' return wrapper class Test(object): def revive(self): print('恢复现场环境') @catch_exception def read_value(self): print('从某个地方读取数据') # 这里可能会发生异常
只需要修改装饰器定义的部分,使用装饰器的地方完全不需要做修改。
下图为正常运行时的运行结果:
下图为发生异常以后捕获并处理异常:
通过添加一个self参数,类外面的装饰器就可以直接使用类里面的各种方法,也可以直接使用类的属性。