ホームページ  >  記事  >  バックエンド開発  >  Python でシングルトン パターンを作成する 5 つの一般的な方法

Python でシングルトン パターンを作成する 5 つの一般的な方法

高洛峰
高洛峰オリジナル
2016-10-18 09:31:521030ブラウズ

いわゆるシングルトンとは、クラスのインスタンスが最初から最後まで 1 回しか作成できないことを意味します。

方法 1

クラスに最初から最後まで最大 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__ メソッドを使用して、クラスのインスタンスが作成されたときにそのクラスのインスタンスをバインドします。 cls._inst が None の場合、クラスがインスタンス化されていないことを意味し、インスタンスを cls._inst にバインドします。最初のインスタンス化で作成されたインスタンスは、今後インスタンス化されるたびに返されます。シングルトンからサブクラスを派生するときは、__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__ が同じ辞書を指すようにするため、インスタンスは同じメソッドとプロパティを共有します。インスタンスの name 属性の設定は、__init__ 内で変更されたか直接変更されたかに関係なく、すべてのインスタンスに影響します。ただし、インスタンス ID は異なります。クラス インスタンスが属性を共有できるが、サブクラスとは共有できないようにするには、Borg._shared_state の代わりに cls._shared_state を必ず使用してください。

インスタンスの ID が異なるため、各インスタンスを辞書キーとして使用できます:

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

この動作が希望どおりでない場合は、次のようにすることができます。 __eq__ メソッドと __hash__ メソッドを 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
    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

キーが使用されている場合、すべてのインスタンスが可能です。

方法 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は同じです。

この例では、Singleton メタクラスを構築し、 __call__ メソッドを使用して関数の動作をシミュレートします。クラス A を構築するときにそのメタクラスを Singleton に設定し、クラス オブジェクト A を作成するときに次のように動作します:

A=Singleton(name, baseds, class_dict), A は実際には Singleton クラスのインスタンスです。

A のインスタンスを作成するとき、A()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__() となり、A のすべてのインスタンスが A_ の属性を指すようになります。たとえば、この方法は実際には方法 1 と同じです。

方法 4

Python の module モジュールはプログラム内で 1 回だけロードされ、それ自体がシングルトンです。モジュールを直接記述し、モジュール内で必要なメソッドと属性をモジュール スコープ内の関数およびグローバル変数として記述することができます。クラスを記述する必要はまったくありません。

そして、モジュールとクラスの利点を組み合わせる方法がいくつかあります:

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

最も簡単な方法:


りー

名前 singleton をインスタンスにバインドすると、singleton が独自のクラスの唯一のオブジェクトになります。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。