🚀
Pythonで自作のSingletonパターンを実装してみる
初めに
今回はDesign patternの中のSingletonに関して利用しようというモチベーションがあり、実装方法も含めて備忘録として記事に残します。
ちなみに、カスタマイズしている故に本来のSingletonとは異なるので、留意してください。
※認識として正しくない場合があるため、その際はご指摘いただけると幸いです。
Singletonパターン
概要
以下はwikipediaより引用したSingletonパターンの説明です。
Singleton パターン(シングルトン・パターン)とは、オブジェクト指向のコンピュータプログラムにおける、デザインパターンの1つである。GoF (Gang of Four; 4人のギャングたち) によって定義された。Singleton パターンとは、そのクラスのインスタンスが1つしか生成されないことを保証するデザインパターンのことである
cf. wikipediaより引用
つまり、1つのプロセスでインスタンスの生成が1つしか許されないものと理解しています。
ユースケース
今回は環境変数の管理で利用したいと思っており、以下の部分を制限したいと思っていました。
- 再インスタンス化によって状態が変わることをブロック
- インスタンス化のたびに状態が変わらないようにするため
- 外部からの書き換えをブロック
- Pythonの場合はインスタンス変数の状態を外部から書き換えられるため
そのため、プロセスの中で意図せず環境変数が変わらないように統制した実装を行うことにしました。
実装
実装としては以下のとおりです。
それ自体をクラスとして利用する想定なので、継承させることはなく必要な変数をkwargsとして受け取ることを想定したクラスになります。
from dataclasses import dataclass
@dataclass(frozen=True)
class Singleton:
_instance = None
value1: int
value2: int
def __new__(cls, **kwargs) -> 'Singleton':
if cls._instance is None:
cls._instance = super(Singleton, cls).__new__(cls)
for key, value in kwargs.items():
# :NOTE dataclassのfrozenで外部から書き換えをブロックしているが、
# 初回コンストラクトしたときもFrozenInstanceErrorとなるため、
# 親クラスの__setattr__で初回のみ書き換えを許容
object.__setattr__(cls._instance, key, value)
return cls._instance
def __init__(self, **kwargs):
if self._instance is not None:
for key, value in kwargs.items():
if getattr(self._instance, key) != value:
raise TypeError('This class is singleton. Can\'t init again')
上記実装のポイントとしては、以下のとおりです。
-
@dataclass(frozen=True)
で状態を不変に設定 - 再インスタンス化の際にインスタンス変数と引数のvalidationを追加
詳細なコードに関してはgithubにあげています(github側では命名を変更しています)。
Discussion