Python でのシングルトン モードの実現方法

シングルトン モードとは、ソフトウェア設計の手法で、特定のクラスが何度インスタンス化されても、常に同じメモリ アドレスを指すようにするものです。この手法により、1つのクラスから 1つのオブジェクトのみが生成されます。
1. モジュールのインポートを活用した方法
基本的な仕組み:Python モジュールをインポートすると、そのモジュールのコードが一度だけ実行され、名前空間がメモリにロードされます。再インポート時には、同じ名前空間が使用されるため、クラスのインスタンスも共有されます。
コード例:
# singleton_module.py
class MySingleton:
    pass

my_instance = MySingleton()

# main.py
import singleton_module

obj_a = singleton_module.my_instance
obj_b = singleton_module.my_instance
print(obj_a is obj_b)  # 結果:True
2. __new__ メソッドをオーバーライドした方法
コード例:
class Singleton:
    _instance = None
    def __init__(self, value):
        self.value = value

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

s1 = Singleton(100)
s2 = Singleton(200)
print(s1.value)  # 結果:100
print(s2.value)  # 結果:100
print(id(s1) == id(s2))  # 結果:True
3. デコレータを活用した方法
コード例:
def singleton_decorator(cls):
    instances = {}
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return wrapper

@singleton_decorator
class MyService:
    def __init__(self, name):
        self.name = name

service1 = MyService('ServiceA')
service2 = MyService('ServiceB')
print(service1.name)  # 結果:ServiceA
print(service2.name)  # 結果:ServiceA
print(id(service1) == id(service2))  # 結果:True
4. マルチスレッド対応のシングルトン
__new__ メソッドを改良し、ロック機構を導入することでマルチスレッド環境下でもシングルトンを維持します。
コード例:
import threading

class Singleton:
    _instance = None
    _lock = threading.RLock()

    def __init__(self):
        pass

    def __new__(cls, *args, **kwargs):
        if cls._instance:
            return cls._instance
        with cls._lock:
            if not cls._instance:
                print('Creating new instance')
                cls._instance = super().__new__(cls)
            return cls._instance

obj1 = Singleton()
obj2 = Singleton()
print(id(obj1) == id(obj2))  # 結果:True
5. メタクラスを活用した方法
Python のメタクラスである type を拡張し、インスタンス生成を制御します。
コード例:
class SingletonMeta(type):
    def __init__(cls, name, bases, attrs):
        super().__init__(name, bases, attrs)
        cls._instance = None

    def __call__(cls, *args, **kwargs):
        if not cls._instance:
            with threading.RLock():
                if not cls._instance:
                    cls._instance = super().__call__(*args, **kwargs)
        return cls._instance

class MySingleton(metaclass=SingletonMeta):
    pass

class AnotherSingleton(MySingleton):
    pass

obj1 = AnotherSingleton()
obj2 = AnotherSingleton()
print(id(obj1) == id(obj2))  # 結果:True

タグ: シングルトン Python デコレータ スレッド メタクラス

5月22日 09:15 投稿