ホームページ >バックエンド開発 >Python チュートリアル >Python でシングルトン モードを実装する 5 つの方法
シングルトン パターンは、一般的に使用されるソフトウェア デザイン パターンであり、このパターンの主な目的は、特定のクラスのインスタンスが 1 つだけ存在するようにすることです。シングルトン オブジェクトは、システム全体で特定のクラスのインスタンスを 1 つだけ表示したい場合に便利です。
たとえば、サーバー プログラムの構成情報はファイルに保存され、クライアントは AppConfig クラスを通じて構成ファイルの情報を読み取ります。プログラムの実行中に構成ファイルの内容をさまざまな場所で使用する必要がある場合、つまり、AppConfig オブジェクトのインスタンスをさまざまな場所で作成する必要がある場合、複数の AppConfig インスタンス オブジェクトが存在することになります。特に構成ファイルに多くのコンテンツが含まれている場合、メモリ リソースが大幅に浪費されます。
実際、AppConfig のようなクラスの場合、プログラムの実行中にインスタンス オブジェクトが 1 つだけ存在することが望まれます。
Python では、さまざまな方法を使用してシングルトン パターンを実装できます。
以下詳細な紹介:
実際、Python モジュールは自然なシングルトン モードです。これは、モジュールが初めてインポートされるときに、.pyc ファイルが2 回目にインポートすると、モジュール コードを再度実行することなく、.pyc ファイルが直接ロードされます。
したがって、シングルトン オブジェクトを取得するには、モジュール内で関連する関数とデータを定義するだけで済みます。
本当にシングルトン クラスが必要な場合は、これを行うことを検討できます:
class Singleton(object): def foo(self): pass singleton = Singleton()
上記のコードをファイル mysingleton.py に保存します。このファイルのオブジェクトを他のファイルにインポートします。このオブジェクトはシングルトン モードのオブジェクトです。
from mysingleton import singleton
def Singleton(cls): _instance = {} def _singleton(*args, **kargs): if cls not in _instance: _instance[cls] = cls(*args, **kargs) return _instance[cls] return _singleton @Singleton class A(object): a = 1 def __init__(self, x=0): self.x = x a1 = A(2) a2 = A(3)
class Singleton(object): def __init__(self): pass @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance
一般に、これでシングルトン モードが完了すると誰もが考えますが、マルチスレッドを使用する場合には問題が発生します。
class Singleton(object): def __init__(self): pass @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance import threading def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start()
プログラムを実行すると、出力結果は次のようになります。
<__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0>
参照 問題はありませんが、実行速度が速すぎるため、__init__ メソッド内に IO 処理が含まれている場合に問題が発生します。
以下では、time.sleep を通じてシミュレーションを行います。上記の __init__ メソッドに次のコードを追加します:
def __init__(self): import time time.sleep(1)
プログラムを再実行すると、結果は次のようになります:
<__main__.Singleton object at 0x034A3410> <__main__.Singleton object at 0x034BB990> <__main__.Singleton object at 0x034BB910> <__main__.Singleton object at 0x034ADED0> <__main__.Singleton object at 0x034E6BD0> <__main__.Singleton object at 0x034E6C10> <__main__.Singleton object at 0x034E6B90> <__main__.Singleton object at 0x034BBA30> <__main__.Singleton object at 0x034F6B90> <__main__.Singleton object at 0x034E6A90>
問題が発生しました。上記の方法で作成されたシングルトンはマルチスレッドをサポートできません。
import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(1) @classmethod def instance(cls, *args, **kwargs): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start() time.sleep(20) obj = Singleton.instance() print(obj)出力結果は次のとおりです。
<__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110>これはほぼ同じですが、小さな問題がまだあります。つまり、time.sleep(20 の後のプログラムの実行時) です。 ) が実行されると、オブジェクトは以下でインスタンス化され、すでにシングルトン モードになっています。
@classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instanceこのようにして、複数のロックをサポートできます。スレッド シングルトンモードが完了します。
import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(1) @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start() time.sleep(20) obj = Singleton.instance() print(obj)この方法で実装されたシングルトン モードには使用上の制限があります。後のインスタンス化は obj = Singleton.instance() を介して行う必要があります。
import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): pass def __new__(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = object.__new__(cls) return Singleton._instance obj1 = Singleton() obj2 = Singleton() print(obj1,obj2) def task(arg): obj = Singleton() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start()出力結果は次のとおりです。
<__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0>このシングルトン モードを使用すると、今後オブジェクトをインスタンス化するとき、オブジェクトのインスタンス化方法は通常の obj = Singleton() と同じになります。 。
例子: class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): pass obj = Foo() # 执行type的 __call__ 方法,调用 Foo类(是type的对象)的 __new__方法,用于创建对象,然后调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。 obj()# 执行Foo的 __call__ 方法
class SingletonType(type): def __init__(self,*args,**kwargs): super(SingletonType,self).__init__(*args,**kwargs) def __call__(cls, *args, **kwargs): # 这里的cls,即Foo类 print('cls',cls) obj = cls.__new__(cls,*args, **kwargs) cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj) return obj class Foo(metaclass=SingletonType): # 指定创建Foo的type为SingletonType def __init__(self,name): self.name = name def __new__(cls, *args, **kwargs): return object.__new__(cls) obj = Foo('xx')シングルトン モードの実装:
import threading class SingletonType(type): _instance_lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with SingletonType._instance_lock: if not hasattr(cls, "_instance"): cls._instance = super(SingletonType,cls).__call__(*args, **kwargs) return cls._instance class Foo(metaclass=SingletonType): def __init__(self,name): self.name = name obj1 = Foo('name') obj2 = Foo('name') print(obj1,obj2)
以上がPython でシングルトン モードを実装する 5 つの方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。