Python 中实现类的单例的方式有很多,在此只介绍次实现方式的内部不为人知的一点:havcls即装饰器外层变量的生命周期问题。 简单的装饰器如下,另说明一下,havcls其实不需要使用字典,至于为什么,大家往后看吧: 代码1️⃣ def singleclass(cls): havcls = {} def decorator(*args, **kwargs): if type(cls) in havcls: return havcls[type(cls)] else: k = cls.__new__(cls, *args, **kwargs) havcls[type(cls)] = k return k return decorator
装饰器用法:
@singleclass class A(object): pass
注意:Python2中此装饰器只能用于以object为基类的类,因为只有object类有__new__方法。
a1 = A() a2 = A() print(id(a1) == id(a2))
输出结果为True
很明显,这就已经达到了单例的效果了。可是问题来了,为什么singleclass装饰器可以实现单例,havcls的生命周期就是关键。
分析:
试验得知,havcls的生命周期是从编译类开始到程序结束,可为什么会出现这种情况,因为装饰器的原理是隐式的更改被装饰代码,也就是在解释器解释道装饰器时,会将装饰器代码和被装饰的代码结合,以上实例可类似看做:
代码2️⃣ A开始 havcls = {} def A(*args, **kwargs): class A1(object): pass if type(A1) in havcls: return havcls[type(A1)] else: k = A1.__new__(A1, *args, **kwargs) havcls[type(A1)] = k return k A结束
只是可以近似看做。。
所以havcls 就变成了全局变量,但是和全局变量又有所不同,如果继续试验就会发现:
代码3️⃣ def singleclass(cls): havcls = {} def decorator(*args, **kwargs): if type(cls) in havcls: return havcls[type(cls)] else: k = cls.__new__(cls, *args, **kwargs) havcls[type(cls)] = k return k print(id(havcls)) return decorator
@singleclass class A(object): pass @singleclass class B(object): pass
a1 = A() b1 = B()
输出结果:4466351192
4466672256
在装饰器每次被解释器解释的时候,会从头开始生成变量,及重新声明一个havcls,由于其命名空间是A 和B 【代码2️⃣】所以不同被装饰的类会持有自己的havcls变量,由此就知道最开始的答案了吧!
如有错误,敬请斧正!