W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
你想在類中定義裝飾器,并將其作用在其他函數(shù)或方法上。
在類里面定義裝飾器很簡單,但是你首先要確認(rèn)它的使用方式。比如到底是作為一個(gè)實(shí)例方法還是類方法。下面我們用例子來闡述它們的不同:
from functools import wraps
class A:
# Decorator as an instance method
def decorator1(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
print('Decorator 1')
return func(*args, **kwargs)
return wrapper
# Decorator as a class method
@classmethod
def decorator2(cls, func):
@wraps(func)
def wrapper(*args, **kwargs):
print('Decorator 2')
return func(*args, **kwargs)
return wrapper
下面是一使用例子:
# As an instance method
a = A()
@a.decorator1
def spam():
pass
# As a class method
@A.decorator2
def grok():
pass
仔細(xì)觀察可以發(fā)現(xiàn)一個(gè)是實(shí)例調(diào)用,一個(gè)是類調(diào)用。
在類中定義裝飾器初看上去好像很奇怪,但是在標(biāo)準(zhǔn)庫中有很多這樣的例子。特別的,@property
裝飾器實(shí)際上是一個(gè)類,它里面定義了三個(gè)方法 getter(), setter(), deleter()
,每一個(gè)方法都是一個(gè)裝飾器。例如:
class Person:
# Create a property instance
first_name = property()
# Apply decorator methods
@first_name.getter
def first_name(self):
return self._first_name
@first_name.setter
def first_name(self, value):
if not isinstance(value, str):
raise TypeError('Expected a string')
self._first_name = value
它為什么要這么定義的主要原因是各種不同的裝飾器方法會(huì)在關(guān)聯(lián)的 property
實(shí)例上操作它的狀態(tài)。因此,任何時(shí)候只要你碰到需要在裝飾器中記錄或綁定信息,那么這不失為一種可行方法。
在類中定義裝飾器有個(gè)難理解的地方就是對(duì)于額外參數(shù) self
或 cls
的正確使用。盡管最外層的裝飾器函數(shù)比如 decorator1()
或 decorator2()
需要提供一個(gè) self
或 cls
參數(shù),但是在兩個(gè)裝飾器內(nèi)部被創(chuàng)建的 wrapper()
函數(shù)并不需要包含這個(gè) self
參數(shù)。你唯一需要這個(gè)參數(shù)是在你確實(shí)要訪問包裝器中這個(gè)實(shí)例的某些部分的時(shí)候。其他情況下都不用去管它。
對(duì)于類里面定義的包裝器還有一點(diǎn)比較難理解,就是在涉及到繼承的時(shí)候。例如,假設(shè)你想讓在A中定義的裝飾器作用在子類B中。你需要像下面這樣寫:
class B(A):
@A.decorator2
def bar(self):
pass
也就是說,裝飾器要被定義成類方法并且你必須顯式的使用父類名去調(diào)用它。你不能使用 @B.decorator2
,因?yàn)樵诜椒ǘx時(shí),這個(gè)類B還沒有被創(chuàng)建。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: