Python建设单例模式的5种常用要领
当前位置:以往代写 > Python教程 >Python建设单例模式的5种常用要领
2019-06-14

Python建设单例模式的5种常用要领

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就是它本身类的独一工具了。

    关键字:

在线提交作业