Pythonの__new__メソッドとシングルトンパターン実装

__new__メソッドの基礎

Pythonでクラス名を括弧付きで記述してオブジェクトを生成する際、インタープリタは最初に__new__メソッドを呼び出してオブジェクト用のメモリを確保します。

__new__object基底クラスから提供される組み込み静的メソッドであり、以下の2つの役割を担っています:

  • メモリ上のオブジェクト用領域を確保すること
  • 生成されたオブジェクトへの参照を返すこと

インタープリタがこの参照を取得すると、それを最初の引数として__init__メソッドに渡します。

__new__は新方式クラス(new-style class)に導入されたメソッドであり、インスタンス構築の前に実行されます。イメージとして、Pythonのクラスには__init__というコンストラクタがありますが、その起動前に__new__が呼び出されます。__new____init__を使用するかを決定でき、他のクラスのコンストラクタを呼び出したり、異なるオブジェクトを返すこともできます。

例えるなら、クラスは工場、__init__は生産工人、原材料は初期化パラメータ、工人は原材料を加工して製品を作成します。一方__new__は工場社長であり、材料を工人に提供するかどうかを決定し、さらに製品が当該工場製かどうかを管理できます。

クラスのインスタンス化

class DataStorage:
    def __init__(self, *args, **kwargs):
        pass

# インスタンス化
storage = DataStorage(100, 200)

クラスオブジェクト作成时会自动调用__new__メソッド。如果__new__メソッド重写,则必须调用其父类的方法,并且返回参照するようにしてください。具体的にはreturn super().__new__(cls)を記述,否则__init__メソッドがメモリを獲得できず、初期化が行われません。

シングルトンパターンへの応用

シングルトンとは、クラスから生成されるオブジェクトがシステム内で唯一のインスタンスしかないことを保証する設計パターンです。以下のコードでは、クラス属性としてinstance = Noneを定義し、シングルトンオブジェクトの参照を保持します。__new__メソッドをオーバーライドし、まずクラス属性がNone空オブジェクトかどうかをチェックします。

class ConfigManager:
    # クラス属性でインスタンス参照を保持
    _instance = None
    
    # __new__メソッドのオーバーライド
    def __new__(cls, *args, **kwargs):
        # 1. クラス属性が空オブジェクトか判定
        if cls._instance is None:
            # 2. 基底クラスのメソッドを呼び出し、最初のオブジェクトにメモリ割り当て
            cls._instance = super().__new__(cls)
        # 3. クラス属性に保存されたオブジェクト参照を返す
        return cls._instance

manager1 = ConfigManager()
print(manager1)

manager2 = ConfigManager()
print(manager2)

実行結果:

<__main__.ConfigManager object at 0x000002298A38F128>
<__main__.ConfigManager object at 0x000002298A38F128>

確認できる通り、manager1とmanager2のオブジェクトメモリアドレスが同一であり、シングルトンパターンが正常に機能しています。

タグ: Python __new__ singleton design-pattern object-oriented-programming

7月21日 23:08 投稿