この質問は、シングルトンデザインパターンが望ましいかどうか、アンチパターンであるかどうか、または宗教戦争の場合ではなく、このパターンがPythonで最もPython的に実装される方法について議論するためのものです。この場合、私は「ほとんどのpythonic」を「最小の驚きの原則」に従うことを定義します。
シングルトンになる複数のクラスがあります(私のユースケースはロガー用ですが、これは重要ではありません)。単に継承したり装飾したりできるときに、追加されたガンフを使用していくつかのクラスを散らかしたくありません。
最良の方法:
方法1:デコレーター
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance
@singleton
class MyClass(BaseClass):
pass
長所
- デコレータは、多くの場合、複数の継承よりも直感的な方法で追加されます。
短所
- MyClass()を使用して作成されたオブジェクトは真のシングルトンオブジェクトですが、MyClass自体はクラスではなく関数なので、そこからクラスメソッドを呼び出すことはできません。またため
m = MyClass(); n = MyClass(); o = type(n)();
、その後m == n && m != o && n != o
方法2:基本クラス
class Singleton(object):
_instance = None
def __new__(class_, *args, **kwargs):
if not isinstance(class_._instance, class_):
class_._instance = object.__new__(class_, *args, **kwargs)
return class_._instance
class MyClass(Singleton, BaseClass):
pass
長所
- それは本当のクラスです
短所
- 多重継承-えー!
__new__
2番目の基本クラスからの継承中に上書きされる可能性がありますか?必要以上に考えなければならない。
方法3:メタクラス
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
#Python2
class MyClass(BaseClass):
__metaclass__ = Singleton
#Python3
class MyClass(BaseClass, metaclass=Singleton):
pass
長所
- それは本当のクラスです
- 自動的に継承をカバー
__metaclass__
その適切な目的のための使用(そして私にそれを知らせた)
短所
- いずれかがあります?
方法4:同じ名前のクラスを返すデコレーター
def singleton(class_):
class class_w(class_):
_instance = None
def __new__(class_, *args, **kwargs):
if class_w._instance is None:
class_w._instance = super(class_w,
class_).__new__(class_,
*args,
**kwargs)
class_w._instance._sealed = False
return class_w._instance
def __init__(self, *args, **kwargs):
if self._sealed:
return
super(class_w, self).__init__(*args, **kwargs)
self._sealed = True
class_w.__name__ = class_.__name__
return class_w
@singleton
class MyClass(BaseClass):
pass
長所
- それは本当のクラスです
- 自動的に継承をカバー
短所
- 新しいクラスを作成するためのオーバーヘッドはありませんか?ここでは、シングルトンにしたいクラスごとに2つのクラスを作成しています。私の場合はこれで問題ありませんが、これがスケーリングされないのではないかと心配しています。もちろん、このパターンをスケーリングするのがあまりにも簡単であるかどうかについては議論の余地があります...
_sealed
属性のポイントは何ですかsuper()
再帰するため、を使用して基本クラスで同じ名前のメソッドを呼び出すことはできません。つまり__new__
、を呼び出す必要があるクラスをカスタマイズしたり、サブクラス化したりすることはできません__init__
。
方法5:モジュール
モジュールファイル singleton.py
長所
- 単純な方が複雑な方がいい
短所
foo.x
またはのFoo.x
代わりに主張する場合Foo().x
)。クラス属性とstatic / classメソッドを使用します(Foo.x
)。