Skip to content

デザインパターン「Lazy Initialization」を使用したPythonの実装例

Published:

Table of contents

Open Table of contents

はじめに

Lazy Initilization(遅延初期化)について解説し、Python における実例を紹介する。

Lazy Initialization とは?

簡潔に言えば、Lazy Initialization はコンポーネントやオブジェクトの初期化をそれが実際に必要になる時点まで遅らせるテクニックである。

このアプローチの一例として、データベースへの接続オブジェクトが挙げられる。データベースへ接続する直前でのみそのオブジェクトを生成することで、不必要な初期化を避けることができる。

利点として、高コストの初期化を避けることができるため、アプリケーションの起動やインスタンスの作成する時間を短縮することができる。

Python での Lazy Initialization の実装方法

class LazyInitExample:
    def __init__(self):
        self._resource = None

    @property
    def resource(self):
        if self._resource is None:
            self._resource = self._initialize_resource()
        return self._resource

    def _initialize_resource(self):
        print("Resourceを初期化中")
        # ここで重いリソースの初期化を行います。以下はシミュレーションです
        resource = "重いリソース"
        return resource

# 使用例:
lazy_init_example = LazyInitExample()
print("最初のアクセス")
print(lazy_init_example.resource)

print("2回目のアクセス")
print(lazy_init_example.resource)

実行結果

最初のアクセス
Resourceを初期化中
重いリソース
2回目のアクセス
重いリソース
class Multiton:
    _instances = {}

    def __new__(cls, *args, **kwargs):
        key = (args, tuple(kwargs.items()))
        if key not in cls._instances:
            instance = super().__new__(cls)
            cls._instances[key] = instance
        return cls._instances[key]

    def __init__(self, *args, **kwargs):
        # ここに初期化コードを書くことができる(必要に応じて)
        pass

# 使用例:
instance1 = Multiton(1, 2, x=3, y=4)
instance2 = Multiton(1, 2, x=3, y=4)
instance3 = Multiton(5, 6, z=7)

assert instance1 is instance2  # True
assert instance1 is not instance3  # True

class LazyMultiton:
    _instances = {}

    @classmethod
    def get_instance(cls, key, *args, **kwargs):
        if key not in cls._instances:
            instance = cls._create_instance(key, *args, **kwargs)
            cls._instances[key] = instance
        return cls._instances[key]

    @classmethod
    def _create_instance(cls, key, *args, **kwargs):
        instance = cls.__new__(cls)
        instance._key = key
        instance._resource = None
        instance.__init__(key, *args, **kwargs)
        return instance

    def __init__(self, key, *args, **kwargs):
        if not hasattr(self, "_initialized"):
            self._resource = self._initialize_resource(*args, **kwargs)
            self._initialized = True

    def _initialize_resource(self, *args, **kwargs):
        print(f"Resource for key '{self._key}' を初期化中")
        # ここで重いリソースの初期化を行うことができます
        resource = f"重いリソース for key '{self._key}'"
        return resource

    @property
    def resource(self):
        return self._resource


# 使用例:
multiton1 = LazyMultiton.get_instance("key1", "other", "parameters")
print("key1 最初のアクセス")
print(multiton1.resource)

multiton2 = LazyMultiton.get_instance("key2", "more", "parameters")
print("key2 最初のアクセス")
print(multiton2.resource)

multiton1_again = LazyMultiton.get_instance("key1", "other", "parameters")
print("key1 2回目のアクセス")
print(multiton1_again.resource)

assert multiton1 is multiton1_again  # True

まとめ

そこまで出現頻度があるわけではないので、忘れがちである。

最近話題の技術書

GitLab のチームビルディングに関する本。

gitlab