🧱 シングルトンは「モジュール」で作る
🧭 はじめに(What)
このページでは、Python におけるシングルトンの定石を整理する。 結論は明確で、Python ではシングルトンを「クラス」で作らない。 代わりに、モジュールそのものをシングルトンとして使うのが最も自然で、読みやすく、テストしやすい。
🎯 ねらい
- GoF 的な Singleton パターンを Python に持ち込む誤りを正す
- Python が本来備えている 「唯一性」の表現方法を理解する
- 過剰設計を避け、意図が一目で伝わる設計を身につける
🧱 問題の背景
Python でシングルトンを実装しようとすると、次のような設計に陥りがちだ。
- クラス +
__new__オーバーライド - メタクラスを使った Singleton
- スレッドセーフ性を理由に lock だらけの実装
これらは一見「ちゃんとしている」ように見えるが、Python では本質的に不要であることが多い。
Python では import は1回だけ評価され、以降は同じモジュールオブジェクトが再利用される という仕様がある。
❌ よくある誤解
🧬 __new__ をオーバーライドすべき?
- GoF の定義に忠実であろうとする発想
- しかし Python では 意図が読み取りづらい
- 実装を見ないと「シングルトンである」ことが分からない
🧠 メタクラス Singleton は高度で安全?
- 高度だが、読む側の認知負荷が高すぎる
- チーム開発では「知らないと読めないコード」になる
🧵 スレッドセーフにしないと危険?
- import 自体は CPython ではスレッドセーフ
- ほとんどの用途(設定・キャッシュ)では問題にならない
スレッドセーフ性を理由に 先に複雑化するのは典型的な過剰設計。
💥 悪い例:クラスベース Singleton
class ConfigSingleton:
_instance = None
_lock = Lock()
def __new__(cls):
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
問題点
- 読まないと意図が分からない
- テスト時の差し替えが面倒
- 「唯一性」以外の情報が多すぎる
この種の実装は GoF の文脈を知らないと理解できない コードになりやすい。
✅ 良い例①:モジュールをそのまま使う
# config.py
DB_HOST = 'localhost'
DB_PORT = 5432
# usage.py
import config
print(config.DB_HOST)
なぜこれで十分か
import configは一度しか評価されない- すでに 「唯一のインスタンス」 が保証されている
- 読めば一発で意図が分かる
Python では モジュール = 自然な Singleton。
✅ 良い例②:遅延生成が必要な場合
# resource.py
_resource = None
def get_resource():
global _resource
if _resource is None:
_resource = create_resource()
return _resource
- 初期化コストが重い場合に有効
- 依存関係を関数境界に閉じ込められる
✅ 良い例③:lru_cache(maxsize=1) を使う
from functools import lru_cache
@lru_cache(maxsize=1)
def get_config():
return load_config()
- 明示的に「1回だけ生成する」ことが分かる
- テストでは
cache_clear()でリセット可能
「一度だけ生成される関数」 という意図がコードから直接読める。
🧠 設計の要点
- Python では モジュールが言語組み込みの Singleton
- 唯一性は import の仕組みが保証している
- 「クラスである必然性」がない限り、クラスは不要
✅ チェックリスト
- クラスである必要は本当にあるか?
- import 1回で目的を満たせないか?
- テスト時に差し替え・初期化し直せるか?
- 読んだ人が「これは Singleton だ」と即理解できるか?
🔚 まとめ
Python においてシングルトンを「設計パターン」として実装しようとすると、 かえって Python らしさを損なう。
- GoF 的 Singleton → 避ける
- モジュール / 関数 + cache → 推奨
シンプルで、読めて、差し替えられる。 それが Python における正しい「唯一性」の設計である。