ほとんどのよく知られている OO 言語では、次のような式SomeClass(arg1, arg2)
は新しいインスタンスを割り当て、インスタンスの属性を初期化し、それを返します。
ほとんどのよく知られている OO 言語では、「インスタンスの属性を初期化する」部分は、コンストラクターを定義することによってクラスごとにカスタマイズできます。これは基本的に、新しいインスタンスで動作する単なるコードのブロックです (コンストラクター式に提供された引数を使用します)。 ) 必要な初期条件を設定します。Python では、これはクラスの__init__
メソッドに対応します。
Python の__new__
ものは、「新しいインスタンスの割り当て」部分の同様のクラスごとのカスタマイズに他なりません。もちろん、これにより、新しいインスタンスを割り当てるのではなく、既存のインスタンスを返すなどの通常とは異なることを行うことができます。したがって、Python では、この部分が必ずしも割り当てに関係しているとは考えるべきではありません。必要なのは__new__
、どこかから適切なインスタンスを思いつくことだけです。
しかし、それはまだ仕事の半分に過ぎず、Python システムは、__init__
後で仕事の残りの半分 ( ) を実行したい場合と実行したくない場合があることを知る方法がありません。その動作が必要な場合は、明示的に言う必要があります。
多くの場合、 のみが必要になるように、または が不要になるようにリファクタリングでき__new__
ます。しかし、本当にやりたいのであれば、Python では実際に「ジョブ」を再定義できるので、必ずしも呼び出しの後に が続くとは限りません。これを行うには、メタクラスを作成し、そのメソッドを定義する必要があります。__new__
__init__
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
ただし、これはおそらく、この状況で実際に保証されるよりも深い魔法です!