9.3 解除一個裝飾器

2018-02-24 15:27 更新

問題

一個裝飾器已經(jīng)作用在一個函數(shù)上,你想撤銷它,直接訪問原始的未包裝的那個函數(shù)。

解決方案

假設裝飾器是通過 @wraps (參考9.2小節(jié))來實現(xiàn)的,那么你可以通過訪問 __wrapped__ 屬性來訪問原始函數(shù):

>>> @somedecorator
>>> def add(x, y):
...     return x + y
...
>>> orig_add = add.__wrapped__
>>> orig_add(3, 4)
7
>>>

討論

直接訪問未包裝的原始函數(shù)在調試、內省和其他函數(shù)操作時是很有用的。但是我們這里的方案僅僅適用于在包裝器中正確使用了 @wraps 或者直接設置了 __wrapped__ 屬性的情況。

如果有多個包裝器,那么訪問 __wrapped__ 屬性的行為是不可預知的,應該避免這樣做。在Python3.3中,它會略過所有的包裝層,比如,假如你有如下的代碼:

from functools import wraps

def decorator1(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('Decorator 1')
        return func(*args, **kwargs)
    return wrapper

def decorator2(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('Decorator 2')
        return func(*args, **kwargs)
    return wrapper

@decorator1
@decorator2
def add(x, y):
    return x + y

下面我們在Python3.3下測試:

>>> add(2, 3)
Decorator 1
Decorator 2
5
>>> add.__wrapped__(2, 3)
5
>>>

下面我們在Python3.4下測試:

>>> add(2, 3)
Decorator 1
Decorator 2
5
>>> add.__wrapped__(2, 3)
Decorator 2
5
>>>

最后要說的是,并不是所有的裝飾器都使用了 @wraps ,因此這里的方案并不全部適用。特別的,內置的裝飾器 @staticmethod@classmethod 就沒有遵循這個約定(它們把原始函數(shù)存儲在屬性 __func__ 中)。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號