最もよく知られているオブジェクト指向言語では、のような式SomeClass(arg1, arg2)
が新しいインスタンスを割り当て、インスタンスの属性を初期化してから返します。
最もよく知られているオブジェクト指向言語では、「インスタンスの属性の初期化」の部分は、コンストラクターを定義することにより、クラスごとにカスタマイズできます。これは、基本的には新しいインスタンスを操作するコードのブロックです(コンストラクター式に提供される引数を使用) )必要な初期条件を設定します。Pythonでは、これはクラスの__init__
メソッドに対応します。
Python __new__
は、「新しいインスタンスの割り当て」部分のクラスごとの同様のカスタマイズにすぎません。もちろん、これにより、新しいインスタンスを割り当てるのではなく、既存のインスタンスを返すなど、異常なことを行うことができます。したがって、Pythonでは、この部分を必ずしも割り当てを伴うものと考えるべきではありません。必要なのは__new__
、どこかから適切なインスタンスが出てくることだけです。
しかし、それはまだ仕事の半分にすぎず、Pythonシステムがジョブの残りの半分(__init__
)を後で実行したい場合とそうでない場合があることを知る方法はありません。その動作が必要な場合は、そのように明示的に言う必要があります。
多くの場合、リファクタリングして、必要なだけ__new__
、または必要ない__new__
、または__init__
すでに初期化されたオブジェクトに対して異なる動作をさせることができます。しかし、本当にやりたいのであれば、Pythonは実際に「仕事」を再定義することを許可しているので、SomeClass(arg1, arg2)
必ずしもが__new__
後に続くとは限りません__init__
。これを行うには、メタクラスを作成し、その__call__
メソッドを定義する必要があります。
メタクラスはクラスの単なるクラスです。また、クラスの__call__
メソッドは、クラスのインスタンスを呼び出したときの動作を制御します。だから、メタクラス「__call__
あなたはクラスを呼び出すときに何が起こるかの方法コントロールは、つまり、インスタンス作成メカニズムを最初から最後まで再定義できます。これは、シングルトンパターンなどの完全に非標準のインスタンス作成プロセスを最もエレガントに実装できるレベルです。実際には、コードの10本の未満の線であなたを実装することができSingleton
、その後でさえいじくるにあなたを必要としないことメタクラス__new__
すべてであり、変えることができます任意の単に追加することによって、シングルトンにそうでない場合は、通常のクラスを__metaclass__ = Singleton
!
class Singleton(type):
def __init__(self, *args, **kwargs):
super(Singleton, self).__init__(*args, **kwargs)
self.__instance = None
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super(Singleton, self).__call__(*args, **kwargs)
return self.__instance
ただし、これはおそらく、この状況で実際に必要とされるよりも深い魔法です。