所謂 函式修飾器,指的是對函式作修飾,基於原函式的處理結果再作加工。你也可以對類別作修飾,也就是所謂類別修飾器,如果你如下撰寫:
@decorator
class Some:
pass
class Some:
pass
其結果相當於:
class Some:
pass
Some = decorator(Some)
pass
Some = decorator(Some)
例如,若 函式修飾器 中的主餐改使用類別封裝:
class FriedChicken:
def getContent(self):
return "不黑心炸雞"
def price(self):
return 49.0
def getContent(self):
return "不黑心炸雞"
def price(self):
return 49.0
若你想要對FriedChicken類別作修飾,使其加上附餐功能,則可以設計一個函式如下:
def dish1(clz):
class SideDishOne:
def __init__(self):
self.meal = clz()
def getContent(self):
return self.meal.getContent() + " | 可樂 | 薯條"
def price(self):
return self.meal.price() + 30.0
return SideDishOne
class SideDishOne:
def __init__(self):
self.meal = clz()
def getContent(self):
return self.meal.getContent() + " | 可樂 | 薯條"
def price(self):
return self.meal.price() + 30.0
return SideDishOne
那麼你可以如下使用,使FriedChicken具有附餐:
def dish1(clz):
class SideDishOne:
def __init__(self):
self.meal = clz()
def getContent(self):
return self.meal.getContent() + " | 可樂 | 薯條"
def price(self):
return self.meal.price() + 30.0
return SideDishOne
@dish1
class FriedChicken:
def getContent(self):
return "不黑心炸雞"
def price(self):
return 49.0
friedchicken = FriedChicken()
print(friedchicken.getContent()) # 不黑心炸雞 | 可樂 | 薯條
print(friedchicken.price()) # 79.0
這是將修飾器使用在類別上的例子。除了使用函式來定義修飾器之外,你也可以使用類別來定義修飾器,在了解如何使用類別定義修飾器之前,你要先了解__call__()方法的作用:
class Some:
def __call__(self, *args):
for arg in args:
print(arg, end=' ')
print()
s = Some()
s(1)
s(1, 2)
s(1, 2, 3)
簡單來說,如果一個物件上具有__call__()方法,則其實例可以使用圓括號來傳入引數,此時會呼叫實例__call__()方法,就如上面的例子所示範的。
所以若要使用類別來定義函式修飾器,其作法為:
class decorator:
def __init__(self, func):
self.func = func
def __call__(self, *args):
result = self.func()
# 對 result 作修飾(傳回)
@decorator
def some(arg):
pass
some(1)
def __init__(self, func):
self.func = func
def __call__(self, *args):
result = self.func()
# 對 result 作修飾(傳回)
@decorator
def some(arg):
pass
some(1)
上例其實相當於:
some = decorator(some)
some(1) # 呼叫 some.__call__(1)
some(1) # 呼叫 some.__call__(1)
也就是使用decorator建立實例,之後對some所參考實例的呼叫,其實都轉換為對__call__()方法的呼叫。所以,若要使用類別來作對 函式修飾器 中點餐程式的修飾,則可以如下:
class dish1:
def __init__(self, func):
self.func = func
def __call__(self):
return self.func() + 30
@dish1
def friedchicken():
return 49.0
print(friedchicken()) # 79.0
若要使用類別實作對類別的修飾器,則原理是:
class decorator:
def __init__(self, clz):
self.clz = clz
def __call__(self, *args):
class wrapper:
def __init__(self, *args):
self.wrapped = self.clz(*args)
# 其它的方法
return wrapper(*args)
@decorator
class Some:
pass
def __init__(self, clz):
self.clz = clz
def __call__(self, *args):
class wrapper:
def __init__(self, *args):
self.wrapped = self.clz(*args)
# 其它的方法
return wrapper(*args)
@decorator
class Some:
pass
上面的例子,其實相當於:
Some = decorator(Some)
s = Some(1, 2) # 其實是呼叫Some.__call__(1, 2)傳回wrapper實例
s = Some(1, 2) # 其實是呼叫Some.__call__(1, 2)傳回wrapper實例
例如若使用類別來對FriedChicken作修飾,則可以如下實作:
class dish1:
def __init__(self, clz):
self.clz = clz
def __call__(self):
class SideDishOne:
def __init__(self, meal):
self.meal = meal
def getContent(self):
return self.meal.getContent() + " | 可樂 | 薯條"
def price(self):
return self.meal.price() + 30.0
return SideDishOne(self.clz())
@dish1
class FriedChicken:
def getContent(self):
return "不黑心炸雞"
def price(self):
return 49.0
friedchicken = FriedChicken()
print(friedchicken.getContent()) # 不黑心炸雞 | 可樂 | 薯條
print(friedchicken.price()) # 79.0