creating-a-singleton-in-python和what-is-a-metaclass-in-python
下面这两段代码的执行结果反映了一个问题:很明显元类的存在会影响__call__和__new__的优先级,请问大神能否分析一下两者执行结果不同的原因?
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
print('__new__')
return cls._instance
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
print('__call__')
return cls._instance
class Foo(Singleton):
pass
print('1')
foo1 = Foo()
print('2')
foo2 = Foo()
print(foo1 is foo2) # True
上面这段代码的执行结果
$ python non_metaclass.py
1
__new__
2
__new__
True
class Singleton(type):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
print('__new__')
return cls._instance
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
print('__call__')
return cls._instance
class Foo(metaclass=Singleton):
# 不兼容Python2
pass
print('1')
foo1 = Foo()
print('2')
foo2 = Foo()
print (foo1 is foo2) # True
上面这段代码的执行结果
$ python metaclass.py
__new__
1
__call__
2
__call__
True
如果描述不够详细,请在评论区留一下言,我再改进。
ここで修正して丁寧に説明します
メタクラスはクラス構造の属性を定義し、クラス内の "__new__" メソッドと "__init__" メソッドはクラス インスタンスの処理に使用されます
私たちが定義するすべてのクラスは、
型のインスタンスとして理解できます。 リーリーそれでは、「__new__」と「__call__」に戻りましょう
メタクラスでは、クラスを定義するときに「__new__」が実行されます。2 つのクラスがこのメタクラスを使用する場合は、2 回実行されます。
リーリーそして、インスタンス化するたびに __call__ が呼び出されます。実際、これは Foo.__new__ と同じです。つまり、Foo が __new__ を定義している場合、メタクラスの __call__ は実行されません。
リーリーメタクラスの「__new__」は、定義した型を変更できます。ここでは Foo をリストとして定義しました。
リーリーメタクラスを正しく理解できる人は非常に少ないので、質問してくださってとても感謝しています。
これはメタクラスが new と call の優先順位に影響を与えるという問題ではなく、メタクラスの __new__ はクラス作成時に一度しか呼び出されないということです。そして、あなたの質問のように、この __new__ はクラスを作成するために使用されます。いつ作成されましたか?インタプリタは Foo クラスを解釈するときに、クラス定義で __metaclass__ 属性を探し、見つかった場合はそれを使用してクラスを作成します。見つからない場合は、組み込み型を使用してクラスが作成されます。もう一度呼び出さないのはなぜでしょうか? メタクラスがすでにクラスを作成しているため、Foo() が呼び出されるたびにクラスを再作成することはできません。出力からも、 foo2 = Foo() が __new__ を出力しないことがわかります。この時点ではクラスはメタクラス、つまり
Singleton
によって作成されているため、そのまま使用を開始できます。私たちが普段使っているクラスと何ら変わらないので、クラスが作成されるたびに新しいオブジェクトが作成されます。なぜ __call__ を使うのでしょうか?Foo はメタクラス Singleton によって作成されたクラスであるため、Foo は Singleton のインスタンス オブジェクトと考えることができます。したがって、Foo() が呼び出されるたびに __call__ が呼び出されます。 __call__ では、作成済みのインスタンス オブジェクトを取得します。ただのシングルトンじゃないの? 。
コードを通して詳しく説明しましょう
リーリー実行後、__call__ 関数の cls は、メタクラス (Foo) で __new__ を初めて呼び出して作成されたクラスであり、cls._instance は Foo のインスタンス オブジェクトであることがわかります。 Foo() が呼び出されるたびに、同じインスタンス オブジェクトが取得されます。 結局のところ、メタクラスはクラスを作成するクラスです。作成されたクラスは、通常定義するクラスと何ら変わりません。