《设计模式之禅》一书中给出解释:
Ensure a class has only one instance, and provide a global point of access to it.
意为:保证一个类只有一个实例,并且向整个系统提供这个实例。
这种模式的应用场景是什么呢?最简单的就是打印机,一个时刻,打印机只可能打印一个文件,只有能一个实例。
有了概念,接下来看python中几种实现方式。
我参考了博客:http://foofish.net/blog/93/python_singleton
本文中所有代码示例均是出自foofish的博客。只是博主没有对示例做解释说明, 仅有代码实现。笔者能力有限,不再重新自编示例,借用foofish给出的示例,解释说明下。
代码
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装饰即可。
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类继承即可。
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即可。
至此,完成了标题中所有内容介绍。