シングルトン設計パターンの長所と短所はこの記事の焦点ではありませんが、この記事では、シングルトン設計パターンの利点と欠点について説明します。可能な限り最善の方法で Python にシングルトンを実装するには、このパターンを Python 的な方法で実装します。ここで、「最も Python 的」とは、「最小の驚きの原則」に従うことを意味します。
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
利点:
欠点:
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
利点:
欠点:
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
利点:
デメリット:
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
利点:
短所:
シングルトン モジュール singleton.py。
長所:
欠点:
方法 2 を使用することをお勧めしますが、基本クラスの代わりにメタクラスを使用することをお勧めします。以下に実装例を示します:
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] class Logger(object): __metaclass__ = Singleton
または Python3 の場合:
class Logger(metaclass=Singleton): pass
クラスが呼び出されるたびに __init__ を実行したい場合は、次のコードを Singleton.__call__ In に追加します。 if ステートメント:
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
メタクラスはクラスのクラス、つまり、クラスはそのメタクラスのインスタンスです。 Python のオブジェクトのメタクラスは、type(obj) によって見つけることができます。通常の新しいクラスは type 型です。 Logger の (唯一の) インスタンスがクラス 'your_module.Logger' であるのと同様に、上記の Logger はクラス 'your_module.Singleton' になります。 Logger() を使用してロガーが呼び出されるとき、Python はまずロガーのメタクラス Singleton に何をすべきかを尋ね、プリエンプティブなインスタンスの作成を可能にします。このプロセスは、Python が __getattr__ を呼び出してその属性をどのように処理するかをクラスに問い合わせる方法と似ており、myclass.attribute を実行してその属性を参照します。
メタクラスは基本的に、呼び出しクラスの意味とその意味の実装方法を決定します。たとえば、メタクラスを使用して Python で C スタイルの構造を再作成する http://code.activestate.com/recipes/498149/ を参照してください。ディスカッション スレッド [メタクラスの具体的な使用例は何ですか? ](https://codereview.stackexchange.com/questions/82786/what-are-some-concrete-use-cases-for-metaclasses) では、一般的に宣言型プログラミング、特にで使用される ORM に関連するいくつかの例も提供しています。 。
この場合、メソッド 2 を使用し、サブクラスで __new__ メソッドが定義されている場合、SubClassOfSingleton() が呼び出されるたびにこのメソッドが実行されます。これは、メソッドを呼び出す責任があるためです。保存されたインスタンスを返します。メタクラスの場合、一意のインスタンスの作成時に一度だけ実行されます。呼び出しクラスの定義をカスタマイズする必要があります。呼び出しクラスの定義は、その型によって決まります。
一般に、メタクラスを使用してシングルトンを実装することは理にかなっています。シングルトンはインスタンスが 1 回だけ作成されるため特別です。一方、メタクラスは、通常のクラスとは異なる動作をさせる、作成されたクラスのカスタム実装です。メタクラスを使用すると、シングルトン クラス定義をカスタマイズする必要がある場合に、より詳細な制御が可能になります。
シングルトンには多重継承は必要ありません (メタクラスは基底クラスではないため)。ただし、継承でクラスのサブクラスを作成するには、シングルトンがclass は最初のメタクラスです。左端のメタクラスは __call__ を再定義します。これが問題になる可能性は低いです。インスタンス ディクショナリはインスタンスの名前空間にないため、誤って上書きされることはありません。
シングルトン パターンは、各クラスが 1 つのことだけを実行する必要があるという意味の「単一責任の原則」に違反しているということも聞きます。こうすることで、コードは独立していてカプセル化されているため、別のコードを変更する必要があるときにコードの動作が壊れることを心配する必要がなくなります。メタクラス実装はこのテストに合格します。メタクラスはパターンを強制し、シングルトンであることを意識する必要のないクラスとサブクラスを作成する責任があります。 メソッド 1 は、「MyClass 自体はクラスではなく関数であるため、クラス メソッドを呼び出すことができません」と指摘したように、このテストに失敗します。
Python 2 および 3 でコードを記述するには、もう少し複雑なスキームが必要です。通常、メタクラスは型クラスのサブクラスであるため、メタクラスを使用して、実行時にメタクラスとして中間基本クラスを動的に作成し、その基本クラスをパブリック シングルトン基本クラスの基本クラスとして使用できます。これは次のように言うは易く行うは難しです:
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
このアプローチの皮肉の 1 つは、サブクラス化を使用してメタクラスを実装していることです。考えられる利点の 1 つは、純粋なメタクラスとは異なり、isinstance(inst, Singleton) が True を返すことです。
別のトピックに関して、お気づきかもしれませんが、元の投稿の基本クラスの実装が間違っていました。クラス内の _instances を参照するには、呼び出し時には実際のクラスがまだ作成されていないため、super() またはクラス メソッドの静的メソッドを使用する必要があります。これはすべて、メタクラスの実装にも当てはまります。
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
以上がPython でシングルトンを実装する最良の方法は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。