python 装饰器实现类的单例

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变量,由此就知道最开始的答案了吧!

 

 

如有错误,敬请斧正!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值