目前在中文网上能搜索到的绝大部分关于装饰器的教程,都在讲如何装饰一个普通的函数。本文介绍如何使用Python的装饰器装饰一个类的方法,同时在装饰器函数中调用类里面的其余方法。本文以捕获一个方法的异常为例来进行说明。python
有一个类Test, 它的结构以下:app
class Test(object):
def __init__(self):
pass
def revive(self):
print('revive from exception.')
# do something to restore
def read_value(self):
print('here I will do something.')
# do something.复制代码
在类中有一个方法read_value()
,这个方法在多个地方被调用。因为某些缘由,方法read_value
有可能随机抛出Exception致使程序崩溃。因此须要对整个方法作try ... except
处理。最丑陋的作法以下面的代码所示:函数
class Test(object):
def __init__(self):
pass
def revive(self):
print('revive from exception.')
# do something to restore
def read_value(self):
try:
print('here I will do something.')
# do something.
except Exception as e:
print(f'exception {e} raised, parse exception.')
# do other thing.
self.revive()复制代码
这样写虽然能够解决问题,可是代码不Pythonic。spa
使用装饰器来解决这个问题,装饰器函数应该写在类里面仍是类外面呢?答案是,写在类外面。那么既然写在类外面,如何调用这个类的其余方法呢?3d
首先写出一个最多见的处理异常的装饰器:rest
def catch_exception(origin_func):
def wrapper(*args, **kwargs):
try:
u = origin_func(*args, **kwargs)
return u
except Exception:
return 'an Exception raised.'
return wrapper
class Test(object):
def __init__(self):
pass
def revive(self):
print('revive from exception.')
# do something to restore
@catch_exception
def read_value(self):
print('here I will do something.')
# do something.复制代码
这种写法,确实能够捕获到origin_func()
的异常,可是若是在发生异常的时候,须要调用类里面的另外一个方法来处理异常,这又应该怎么办?答案是给wrapper增长一个参数:self.code
代码变为以下形式:cdn
def catch_exception(origin_func):
def wrapper(self, *args, **kwargs):
try:
u = origin_func(self, *args, **kwargs)
return u
except Exception:
self.revive() #不用顾虑,直接调用原来的类的方法
return 'an Exception raised.'
return wrapper
class Test(object):
def __init__(self):
pass
def revive(self):
print('revive from exception.')
# do something to restore
@catch_exception
def read_value(self):
print('here I will do something.')
# do something.复制代码
只须要修改装饰器定义的部分,使用装饰器的地方彻底不须要作修改。blog
下图为正常运行时的运行结果:
教程
下图为发生异常之后捕获并处理异常:
经过添加一个self参数,类外面的装饰器就能够直接使用类里面的各类方法,也能够直接使用类的属性。