Python 装饰器装饰类中的方法

目前在中文网上能搜索到的绝大部分关于装饰器的教程,都在讲如何装饰一个普通的函数。本文介绍如何使用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参数,类外面的装饰器就能够直接使用类里面的各类方法,也能够直接使用类的属性。

相关文章
相关标签/搜索