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�节�外一个关于类装饰器的有用的例�。