python之metaclass+singleton(三)

Singleton

singleton(单例模式)

《设计模式之禅》一书中给出解释:
Ensure a class has only one instance, and provide a global point of access to it.
意为:保证一个类只有一个实例,并且向整个系统提供这个实例。
这种模式的应用场景是什么呢?最简单的就是打印机,一个时刻,打印机只可能打印一个文件,只有能一个实例。

python实现

有了概念,接下来看python中几种实现方式。
我参考了博客:http://foofish.net/blog/93/python_singleton
本文中所有代码示例均是出自foofish的博客。只是博主没有对示例做解释说明, 仅有代码实现。笔者能力有限,不再重新自编示例,借用foofish给出的示例,解释说明下。

1,实现方法一:

代码

def singleton(cls):
    instances = {}
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return wrapper

@singleton
class Foo(object):
    pass

foo1 = Foo()
foo2 = Foo()
print foo1 is foo2  #运行结果为True

利装饰器实现,如果你压根对python装饰器这种语法没有了解,建议先去看下装饰器的基本概念,能够理解基础装饰器再来看。如果你了解装饰器,并且了解在类定义上使用装饰器,那么就能够立刻理解这段代码。如果你仅仅了解装饰器基本概念,上段代码:

@singleton
class Foo(object):
    pass
foo1 = Foo()

#等同于
class Foo(object):
    pass
foo1 = singleton(Foo)

把类(或者说类对象)Foo传给函数singleton,singleton中只是定义了一个instance字典,正真在执行是singleton定义的wrapper函数。因此第一次实例foo1时,if为真,执行完并返回cls(就是Foo)创建的对象。实例foo2时,if为假,此时instances[cls]就是foo1,实现了只有一个实例的功能。如果希望你定义的其他类是单例,那就直接@singleton装饰即可。

2,实现方法二

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, 
                cls).__new__(cls, *args, **kwargs)
        return cls._instance

class Foo(Singleton):
    pass

__new__方法不用多说,第一节中已经介绍过,此处Foo从类Singleton继承在实例化时会默认调用父类的已经复写过的__new__方法,原理和方法一类似。如果想自己定义的类是单例形式,只要从Singleton类继承即可。

3,实现方法三

class Singleton(type):
    def __call__(cls, *args, **kwargs):
        print 'call Singleton __call__'
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, 
                                  cls).__call__(*args, **kwargs)
        return cls._instance

class Foo(object):
    __metaclass__ = Singleton
foo1 = Foo()
foo2 = Foo()
print foo1 is foo2  #运行结果为True

用“元类”实现。这是非常经典的一个小例子,如果你看了之前两节,并且能够读懂这个实例,说明正真理解元类了。如果没看懂,请思考如下问题:
1,不用Foo类去创建实例,仅仅只有Foo和Singleton定义,执行脚本,会不会像第二节中打印出print语句?
2,__call__在哪里调用?

还记得__call__是怎么调用的吗?是一个类实例化出来的对象obj,直接通过obj ()形式调用了 __call__。此处的元类根本没有复写__new__和__init__方法,Foo类就是Singleton创建出来的一个普通的类(就是一个Singleton类的对象,实例),因此Foo()会调用Singleton的__call__。__call__中限定了只能新建一个Foo类的对象。如果想要定义的类是单例的,只要定义类时指定__metaclass__ = Singleton即可。

至此,完成了标题中所有内容介绍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值