单例模式:保证某个类中只应该有一个实例。
这里我们将使用Python Cookbook的代码
方法一,继承Singleton
类:
class Singleton(object):
"""一个Python风格的单例模式"""
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'_inst'):
cls._inst = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._inst
if __name__ == '__main__':
class SingleSpam(Singleton):
def __init__(self, s):
self.s = s
def __str__(self):
return self.s
s1 = SingleSpam('spam')
s2 = SingleSpam('eggs')
print id(s1), s1
print id(s2), s2
通过__new__
方法,将类的实例在创建的时候绑定到类属性_inst
上。如果cls._inst
为None
,说明类还未实例化,实例化并将实例绑定到cls._inst
,以后每次实例化的时候都返回第一次实例化创建的实例。注意从Singleton
派生子类的时候,不要重载__new__
。
关于单例的一个常见议题是子类化。Singleton类的编写方式意味着它的每个子类,包括直接子类或者间接子类,都能个分别获得一个独立的实例(这个问题是Cookbook原文,经过下面的实例得出这个结果应该是在Python之后的版本(现在用的是2.7,书中是2.4)有所改进,所以这段文字应该是错误的)。从字面意思上讲,似乎违背了单一实例的元组,不过这依赖于”单一”的具体含义:
class Foo(Singleton):pass
class Bar(Foo): pass
f = Foo()
b = Bar()
print f is b, isinstance(f, Foo), isinstance(b, Foo)
#True, True, True
方法二:用Borg惯用法来避免”单例”模式
class Borg(object):
_shared_state={}
def __new__(cls,*args,**kwargs):
obj=super(Borg,cls).__new__(cls,*args,**kwargs)
obj.__dict__=cls._shared_state
return obj
重载子类的__new__
(少数才需要),重载的是Borg.__new__
。
将所有实例的__dict__
指向同一个字典,这样实例就共享相同的方法和属性。对任何实例的名字属性的设置,无论是在__init__
中修改还是直接修改,所有的实例都会受到影响。不过实例的id是不同的。要保证类实例能共享属性,但不和子类共享,注意使用cls._shared_state
,而不是Borg._shared_state
。
使用:
if __name__=='__main__':
class Example(Borg):
name = None
def __init__(self, name=None):
if name:
self.name = name
def __str__(self):
return 'name->%s' % self.name
a = Example('Lara')
b = Example()
print a, b
c = Example('Join')
print a, b, c
b.name = 'Seven'
print a, b, c
#结果
name->Lara name->Lara
name->Join name->Join name->Join
name->Seven name->Seven name->Seven
但这其中Example的实例id是不同的,既然我们没有定义特殊方法__eq__
和__hash__
,则每个实例都可以作为字典的独立的键。
adict = {}
j = 0
for i in a, b, c:
adict[i] = j
j = j + 1
for i in a, b ,c:
print i, adict[i]
#结果
name->Seven 0
name->Seven 1
name->Seven 2
如果这种行为不是你想要的,可以为Borg类添加eq和hash方法,使其更接近于单例模式的行为:
class Borg(object):
_shared_state={}
def __new__(cls,*args,**kwargs):
obj=super(Borg,cls).__new__(cls,*args,**kwargs)
obj.__dict__=cls._shared_state
return obj
def __hash__(self):
return 1
def __eq__(self,other):
try:
return self.__dict__ is other.__dict__
except:
return False
if __name__=='__main__':
class Example(Borg):
pass
a=Example()
b=Example()
c=Example()
adict={}
j=0
for i in a,b,c:
adict[i]=j
j+=1
for i in a,b,c:
print adict[i]
#结果
name->Seven 2
name->Seven 2
name->Seven 2