Python 裝飾器裝飾類中的方法

目前在中文網(wǎng)上能搜索到的絕大部分關(guān)于裝飾器的教程,都在講如何裝飾一個普通的函數(shù)。本文介紹如何使用Python的裝飾器裝飾一個類的方法,同時在裝飾器函數(shù)中調(diào)用類里面的其他方法。本文以捕獲一個方法的異常為例來進(jìn)行說明。

有一個類Test, 它的結(jié)構(gòu)如下:

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(),這個方法在多個地方被調(diào)用。由于某些原因,方法read_value有可能隨機(jī)拋出Exception導(dǎo)致程序崩潰。所以需要對整個方法做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。

使用裝飾器來解決這個問題,裝飾器函數(shù)應(yīng)該寫在類里面還是類外面呢?答案是,寫在類外面。那么既然寫在類外面,如何調(diào)用這個類的其他方法呢?

首先寫出一個最常見的處理異常的裝飾器:

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()的異常,但是如果在發(fā)生異常的時候,需要調(diào)用類里面的另一個方法來處理異常,這又應(yīng)該怎么辦?答案是給wrapper增加一個參數(shù):self.

代碼變?yōu)槿缦滦问剑?/p>

def catch_exception(origin_func):
    def wrapper(self, *args, **kwargs):
        try:
            u = origin_func(self, *args, **kwargs)
            return u
        except Exception:
            self.revive() #不用顧慮,直接調(diào)用原來的類的方法
            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.

只需要修改裝飾器定義的部分,使用裝飾器的地方完全不需要做修改。

下圖為正常運(yùn)行時的運(yùn)行結(jié)果:


正常運(yùn)行

下圖為發(fā)生異常以后捕獲并處理異常:


發(fā)生異常

通過添加一個self參數(shù),類外面的裝飾器就可以直接使用類里面的各種方法,也可以直接使用類的屬性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容