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


在前面的文章中,我们已经编写了函数装饰器来管理函数调用,但是正如我们已经见到的,从Python2.6和Python3.0起装饰器已被扩展,因此也能在类上使用。如同前面所提到的,尽管类装饰器与函数装饰器在概念上很相像,但类装饰器是在类上使用的一一它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例。和函数装饰器一样,类装饰器其实只是可选的语法糖,尽管很多人相信,它们使得程序员的意图更为明显并且能使不正确的调用或错失的调用最小化。

由于类装饰器可以拦截实例创建调用,因此它们可以用来管理一个类的所有实例,或者扩展这些实例的接口。为了说明这点,这里的第一个类装饰器示例做了前一项工作一一一管理一个类的所有实例。这段代码实现了传统的单例编程模式,其中每个类最多只有一个实例存在。它的singleton函数定义并返回一个用于管理实例的函数,同时@语法在这个函数中自动包装了一个主体类:

instances = {}def singleton(aClass):
    def onCall(*args, **kwargs):
        if aClass not in instances:
            instances[aClass] = aClass(*args, **kwargs)
        return instances[aClass]
    return onCall12345678

为了使用它,对施行单一实例模型的类进行装饰:

@singleton
class Person:
    def __init__(self, name, hours, rate):
        self.name = name
        self.hours = hours
        self.rate = rate
        
    def pay(self):
        return self.hours * self.rate
    
@singleton
class Spam:
    def __init__(self, val):
        self.attr = val
        
bob = Person('Bob', 40, 10)print(bob.name, bob.pay())sue = Person('Sue', 50, 15)print(sue.name, sue.pay())X = Spam(1)Y = Spam(2)print(X.attr, Y.attr)123456789101112131415161718192021222324

现在,当稍后使用PersonSpam类来创建一个实例的时候,装饰器提供的包装逻辑层把实例构建调用指向了onCall,它反过来保证不管进行了多少次构造调用,每个类只有单独一个实例。这段代码的输出如下:

Bob 400Bob 4001 1123

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