Python建设单例模式的5种常用要领
所谓单例,是指一个类的实例从始至终只能被建设一次。
要领1
假如想使得某个类从始至终最多只有一个实例,利用__new__要了解很简朴。Python中类是通过__new__来建设实例的:
class Singleton(object): 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 A(Singleton): def __init__(self,s): self.s=s a=A('apple') b=A('banana') print id(a),a.s print id(b),b.s
功效:
29922256 banana
29922256 banana
通过__new__要领,将类的实例在建设的时候绑定到类属性_inst上。假如cls._inst为None,说明类还未实例化,实例化并将实例绑定到cls._inst,今后每次实例化的时候都返回第一次实例化建设的实例。留意从Singleton派生子类的时候,不要重载__new__。
要领2:
有时候我们并不体贴生成的实例是否具有同一id,而只体贴其状态和行为方法。我们可以答允很多个实例被建设,但所有的实例都共享状态和行为方法:
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
将所有实例的__dict__指向同一个字典,这样实例就共享沟通的要领和属性。对任何实例的名字属性的配置,无论是在__init__中修改照旧直接修改,所有的实例城市受到影响。不外实例的id是差异的。要担保类实例能共享属性,但反体面类共享,留意利用cls._shared_state,而不是Borg._shared_state。
因为实例是差异的id,所以每个实例都可以做字典的key:
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]
功效:
0
1
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]
功效:
2
2
2
所有的实例都能当一个key利用了。
要领3
当你编写一个类的时候,某种机制会利用类名字,基类元组,类字典来建设一个类工具。新型类中这种机制默认为type,并且这种机制是可编程的,称为元类__metaclass__ 。
class Singleton(type): def __init__(self,name,bases,class_dict): super(Singleton,self).__init__(name,bases,class_dict) self._instance=None def __call__(self,*args,**kwargs): if self._instance is None: self._instance=super(Singleton,self).__call__(*args,**kwargs) return self._instance if __name__=='__main__': class A(object): __metaclass__=Singleton a=A() b=A() print id(a),id(b)
功效:
34248016 34248016
id是沟通的。
#p#分页标题#e#
例子中我们结构了一个Singleton元类,并利用__call__要领使其可以或许模仿函数的行为。结构类A时,将其元类设为Singleton,那么建设类工具A时,行为产生如下:
A=Singleton(name,bases,class_dict),A其实为Singleton类的一个实例。
建设A的实例时,A()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__(),这样就将A的所有实例都指向了A的属性_instance上,这种要领与要领1其实是沟通的。
要领4
python中的模块module在措施中只被加载一次,自己就是单例的。可以直接写一个模块,将你需要的要领和属性,写在模块中当做函数和模块浸染域的全局变量即可,基础不需要写类。
并且尚有一些综合模块和类的利益的要领:
class _singleton(object): class ConstError(TypeError): pass def __setattr__(self,name,value): if name in self.__dict__: raise self.ConstError self.__dict__[name]=value def __delattr__(self,name): if name in self.__dict__: raise self.ConstError raise NameError import sys sys.modules[__name__]=_singleton()
python并不会对sys.modules举办查抄以确保他们是模块工具,我们操作这一点将模块绑定向一个类工具,并且今后城市绑定向同一个工具了。
将代码存放在single.py中:
>>> import single >>> single.a=1 >>> single.a=2
ConstError
>>> del single.a
ConstError
要领5
最简朴的要领:
class singleton(object): pass singleton=singleton()
将名字singleton绑定到实例上,singleton就是它本身类的独一工具了。