9.12 使用装饰器扩充类的功能¶
问题¶
ä½ æƒ³é€šè¿‡å��çœ�或者é‡�写类定义的æŸ�部分æ�¥ä¿®æ”¹å®ƒçš„è¡Œä¸ºï¼Œä½†æ˜¯ä½ å�ˆä¸�希望使用继承或元类的方å¼�。
解决方案¶
这�情况�能是类装饰器最好的使用场景了。例如,下�是一个�写了特殊方法 __getattribute__ 的类装饰器,
�以打�日志:
def log_getattribute(cls):
# Get the original implementation
orig_getattribute = cls.__getattribute__
# Make a new definition
def new_getattribute(self, name):
print('getting:', name)
return orig_getattribute(self, name)
# Attach to the class and return
cls.__getattribute__ = new_getattribute
return cls
# Example use
@log_getattribute
class A:
def __init__(self,x):
self.x = x
def spam(self):
pass
下�是使用效果:
>>> a = A(42)
>>> a.x
getting: x
42
>>> a.spam()
getting: spam
>>>
讨论¶
类装饰器通常å�¯ä»¥ä½œä¸ºå…¶ä»–高级技术比如混入或元类的一ç§�é�žå¸¸ç®€æ´�的替代方案。 比如,上é�¢ç¤ºä¾‹ä¸çš„å�¦å¤–一ç§�实现使用到继承:
class LoggedGetattribute:
def __getattribute__(self, name):
print('getting:', name)
return super().__getattribute__(name)
# Example:
class A(LoggedGetattribute):
def __init__(self,x):
self.x = x
def spam(self):
pass
è¿™ç§�方案也行得通,但是为了去ç�†è§£å®ƒï¼Œä½ 就必须知é�“方法调用顺åº�ã€�super() 以å�Šå…¶å®ƒ8.7å°�节介ç»�的继承知识。
æŸ�ç§�程度上æ�¥è®²ï¼Œç±»è£…é¥°å™¨æ–¹æ¡ˆå°±æ˜¾å¾—æ›´åŠ ç›´è§‚ï¼Œå¹¶ä¸”å®ƒä¸�会引入新的继承体系。它的è¿�行速度也更快一些,
å› ä¸ºä»–å¹¶ä¸�ä¾�èµ– super() 函数。
å¦‚æžœä½ æƒ³åœ¨ä¸€ä¸ªç±»ä¸Šé�¢ä½¿ç”¨å¤šä¸ªç±»è£…饰器,那么就需è¦�注æ„�下顺åº�问题。 例如,一个装饰器A会将其装饰的方法完整替æ�¢æˆ�å�¦ä¸€ç§�实现, 而å�¦ä¸€ä¸ªè£…饰器Bå�ªæ˜¯ç®€å�•çš„åœ¨å…¶è£…é¥°çš„æ–¹æ³•ä¸æ·»åŠ ç‚¹é¢�外逻辑。 那么这时候装饰器A就需è¦�放在装饰器Bçš„å‰�é�¢ã€‚
ä½ è¿˜å�¯ä»¥å›žé¡¾ä¸€ä¸‹8.13å°�节å�¦å¤–一个关于类装饰器的有用的例å�。