分类目录:《系统学习Python》总目录


函数装饰器是如此有用,以至于Python2.X和Python3.X都扩展了这一模式,允许装饰器应用于类和函数。简而言之,类装饰器类似于函数装饰器,但它们是在一条class语句的末尾运行,并把一个类名重新绑定到一个可调用对象。同样,它们可以用来在类一创建后就管理它们,或者当随后创建实例的时候插人一层包装逻辑来管理实例。代码结构如下:

def decorator(aClass):pass@decoratorclass C:pass

被映射为下列等价代码:

def decorator(aClass):passclass C:passC = decorator(C)

类装饰器也可以扩展类自身,或者返回一个拦截了随后的实例创建调用的代理对象。例如,在文章《系统学习Python——类(class):静态方法(staticmethod)和类方法(classmethod)-[实例:用类方法计数]》的示例中,我们可以使用这个钩子来自动地扩展需要实例计数器或任何其他所需数据的类:

def count(aClass):aClass.numInstances = 0return aClass@countclass Spam:pass@countclass Sub(Spam):pass@countclass Other(Spam):pass

事实上,正如所编写的那样,该装饰器可被用于类或函数,我们可以在初始化对象属性之后,返回在这两种上下文中定义的对象:

def count(aClass):aClass.numInstances = 0return aClass@countdef spam():pass@countclass Sub:pass@countclass Other:passprint(spam.numInstances)print(Other.numInstances)

输出:

00

尽管这个装饰器管理了一个函数或者类本身,正如我们将在后面的文章看到的,类装饰器也可以通过拦截构造函数,并将新的实例对象包在一个代理(这个代理会部署属性访问工具来拦截之后的属性访问请求)中,来管理一个实例的全部接口,下面是这个模型的简单版本:

def decorator(cls):class Proxy:def __inir__(self, *args):self.wrapper = cls(*args)def __getattr__(self, name):return getattr(self.wrapper, name)return Proxy@decoratorclass C:passX = C()

而元类是一种类似的基于类的高级工具,其用途往往与类装饰器有所重合。它们提供了一种备选的模型,能把一个类对象的创建路由到顶级type类的一个子类,在一条class语句的最后。为了获得对一个新的类对象创建或初始化的控制,一个元类通常重新定义type类的__new__或者__init__方法(这种做法通常用于拦截这两种方法之一)。最终效果就像类装饰器一样,定义了在类创建时自动运行的代码。在这里,这一步将类名绑定到一个用户定义元类的调用结果。事实上,一个元类完全可以不必是一个类。我们将探讨这种模糊了元类与装饰器之间区别的可能性,并且甚至比较这两种工具在许多不同场景中的功能上的等价性。

类装饰器和元类这两种方案都可以用来扩展一个类或返回一个任意的对象来替代它一一一这是一种几乎拥有无限的、基于类的定制化可能性的协议。我们后面会看到,元类也可以定义处理它们实例类的方法,而不是这些实例类的普通实例一一这是一种和类方法很相似的技术,而且可以用类装饰器代理中的方法和数据来模拟实现,或者甚至是一个返回一个元类实例的类装饰器。

参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.