python単例モードの実現

6618 ワード

単例モードはwikipediaの解釈を見る:
単例モードは、単子モードとも呼ばれ、よく使われるソフトウェア設計モードである.このモードを適用する場合、単一のオブジェクトのクラスは、1つのインスタンスのみが存在することを保証する必要があります.
多くの場合、システム全体が1つのグローバルオブジェクトを持つだけで、システム全体の動作を調整するのに役立ちます.たとえば、あるサーバ・プログラムでは、サーバの構成情報がファイルに格納され、これらの構成データは1つのインスタンス・オブジェクトによって統一的に読み出され、サービス・プロセス内の他のオブジェクトは、このインスタンス・オブジェクトによってこれらの構成情報を取得します.この方法により、複雑な環境での構成管理が簡素化されます.
単一のモデルを実現するための考え方は、次のとおりです.
  • クラスは、オブジェクトの参照(常に同じ)とインスタンスを取得する方法(通常getInstanceという名前を使用する静的メソッドでなければならない)を返すことができます.
  • このメソッドを呼び出すと、クラスが保持する参照が空でない場合、この参照が返され、クラスが保持する参照が空である場合、クラスのインスタンスが作成され、クラスが保持する参照にインスタンスの参照が付与されます.
  • 同時に、クラスのコンストラクション関数をプライベートメソッドとして定義し、他のコードはクラスのコンストラクション関数を呼び出すことによってクラスのオブジェクトをインスタンス化することができず、クラスが提供する静的メソッドによってのみクラスの唯一のインスタンスを得ることができます.

  • まず、pythonはプライバシーを強制しないため、Javaのようにアクセス権限が厳格に実行されないため、プライベートコンストラクション関数がないという説は、機密情報にアクセスしないことを自覚しているからです.次にpythonで最も近い構造関数は__new__()であるが,これはあまり用いられない.通常、__init__(self)を使用して、作成したオブジェクトを変更します(selfはインスタンス自体を表します).最後に、pythonは関数式プログラミングとオブジェクト向けプログラミングをサポートします.
    次に、2つのマルチスレッドセキュリティの単一モードpython実装について説明します.
    1.怠け者式(二重ロック):
    # test.py
    import threading
    import time
    
    
    class LazySingleton(object):
        #    ,__             
        #        
        __lock = threading.Lock()
    
        def __init__(self):
            print('         ')
            #     5s 
            time.sleep(5)
    
        #        ,   java   ( )  
        @classmethod
        def get_instance(cls, *args, **kwargs):
            try:
                #      __instance,           ,     
                LazySingleton.__instance
                return LazySingleton.__instance
            except:
                #    with           ,         
                #       GIL 
                with LazySingleton.__lock:
                    try:
                        #      __instance,           ,     
                        LazySingleton.__instance
                        return LazySingleton.__instance
                    except:
                        #  LazySingleton       __instance,   Java    (    )
                        # __             ,       ,            ,        
                        LazySingleton.__instance = LazySingleton()
                        return LazySingleton.__instance
    
    
    if __name__ == "__main__":
        def task():
            #   LazySingleton   /  
            obj = LazySingleton.get_instance()
            print(obj)
    
    
        #         
        for i in range(10):
            t = threading.Thread(target=task)
            t.start()
    

    実行のコミット:
    ssh://[email protected]:22/opt/appl/anaconda3/bin/python -u /opt/appl/pycharm-projects/spark_streaming_test/test.py
             
    <__main__.lazysingleton object="" at="">
    <__main__.lazysingleton object="" at="">
    <__main__.lazysingleton object="" at="">
    <__main__.lazysingleton object="" at="">
    <__main__.lazysingleton object="" at="">
    <__main__.lazysingleton object="" at="">
    <__main__.lazysingleton object="" at="">
    <__main__.lazysingleton object="" at="">
    <__main__.lazysingleton object="" at="">
    <__main__.lazysingleton object="" at="">
    
    Process finished with exit code 0
    

    2.装飾器pythonの関数式プログラミングが分からない場合は、廖雪峰先生のpython関数式プログラミングの章を読むことをお勧めします.そうしないと、次のコードの理解が難しくなります.
    pythonは装飾器で単例モードを実現する考え方が少し変わったが,単例のクラスに何の変更もせず,このインスタンスを得る方法を書く必要がなく,正常なクラスと変わらない.
    # test2.py
    import threading
    from functools import wraps
    import time
    
    
    class Decorator(object):
        #        ,       ,   Java     
        __lock = threading.Lock()
        __instance = None
    
        #         ,cls      
        #           ,   Java   ( )  
        @staticmethod
        def singleton(cls):
            #         ,wraps         ,          
            @wraps(cls)
            def __wrapper(*args, **kw):
                #      __instance      ,     
                if Decorator.__instance is None:
                    #    with           ,         
                    #       GIL 
                    with Decorator.__lock:
                        #      __instance      ,     
                        if Decorator.__instance is None:
                            #      
                            Decorator.__instance = cls(*args, **kw)
                        return Decorator.__instance
                return Decorator.__instance
    
            #           
            return __wrapper
    
    
    # singleton        ,             ,       
    #    :DecoratorSingleton()      singleton(DecoratorSingleton())
    # lock      
    @Decorator.singleton
    class DecoratorSingleton(object):
        #      
        def __init__(self, name):
            print('my name is ' + name)
            #     5s
            time.sleep(5)
    
    
    if __name__ == "__main__":
        #         
        def task():
            #   DecoratorSingleton   /  
            obj = DecoratorSingleton('dong')
            print(obj)
    
    
        #         
        for i in range(10):
            t = threading.Thread(target=task)
            t.start()
    

    実行のコミット:
    ssh://[email protected]:22/opt/appl/anaconda3/bin/python -u /opt/appl/pycharm-projects/spark_streaming_test/test2.py
    my name is dong
    <__main__.decoratorsingleton object="" at="">
    <__main__.decoratorsingleton object="" at="">
    <__main__.decoratorsingleton object="" at="">
    <__main__.decoratorsingleton object="" at="">
    <__main__.decoratorsingleton object="" at="">
    <__main__.decoratorsingleton object="" at="">
    <__main__.decoratorsingleton object="" at="">
    <__main__.decoratorsingleton object="" at="">
    <__main__.decoratorsingleton object="" at="">
    <__main__.decoratorsingleton object="" at="">
    
    Process finished with exit code 0
    

    装飾器を用いて実現される単例モードは極めて柔軟であり,クラスのみならず方法にも用いられ,方法による結果を単例化することができる.
    Pythonは__new__()の書き換えを利用して単例を実現することもでき、興味のある学生は自分で研究することができる.