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參數,類外面的裝飾器就可以直接使用類里面的各種方法,也可以直接使用類的屬性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM