python 如何用修饰符打造一个单例

python的官方wiki给出了一个用修饰符实现的单例,如下:

def singleton(cls):
    instance = cls()
    instance.__call__ = lambda: instance
    return instance

@singleton
class Highlander:
    x = 100

本文主要就这个单例背后的原理展开剖析,其实这里最重要的结论是:Highlander已经是”Highlander”的实例了,为了说明这个事实,我们先看一些熟悉的东西:

class Highlander:
    x = 100

if __name__ == '__main__':

    h = Highlander()

    print type(h)
    print type(Highlander)

这里按常规方式定义了类Hightlander,输出如下:

<type 'classobj'>
<type 'instance'>

这说明Highlander是类,而 h 是 Hightlander的一个实例。但是将Hightlander用修饰符修饰后,代码如下:

def singleton(cls):
    instance = cls()
    instance.__call__ = lambda: instance
    return instance

@singleton
class Highlander:
    x = 100

if __name__ == '__main__':

    h = Highlander()

    print type(h)
    print type(Highlander)

输出如下:

<type 'instance'>
<type 'instance'>

可见,Highlander已经确实成为实例了,即实例的名字与类的名字相同,而原来的类名被屏蔽了,那么 h = Highlander() 又是什么呢?h 实际上是 call的返回结果,我们可以再做一个实验:

def singleton(cls):
    instance = cls()
    instance.__call__ = lambda: 1
    return instance

@singleton
class Highlander:
    x = 100

if __name__ == '__main__':

    h = Highlander()

    print type(h)
    print type(Highlander)

输出如下:

<type 'int'>
<type 'instance'>

可见,此时 h 就变成整型了,已经跟Handlander没有关系了。

这一切的关键在于修饰符到底是怎么工作的,简单点说,修饰符会有如下效果:

def fun1(f):
    ...

@fun1
def fun2():
    ...

等价于:

def fun1(f):
    ...

def fun2():
    ...

fun2 = fun1(fun2)

也就是说,fun2被定义了2次,第一次是原生的,第二次又被fun1定义了一下,所以最终的fun2是fun1的返回值。

现在回到本文,也就是说实现单例的方法等同如如下代码:

def singleton(cls):
    instance = cls()
    instance.__call__ = lambda: instance
    return instance

class Highlander:
    x = 100

Highlander = singleton(Highlander)

传入singleton的参数是类,然后第一步是生成了这个类的一个实例,第二步是定义了这个实例的__call__函数,第三步是将这个实例返回,singleton的返回值就是类Highlander的实例,而从此以后,类名Highlander就消失了(被屏蔽了),由此实现了单例。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值