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
如果描述不够详细,请在评论区留一下言,我再改进。
Saya akan mengubah suainya di sini dan menerangkannya dengan teliti
Metaclass mentakrifkan atribut struktur kelas, dan kaedah "__new__" dan "__init__" dalam kelas digunakan untuk memproses kejadian kelas
Setiap kelas yang kami takrifkan boleh difahami sebagai contoh jenis
Baiklah, kembali kepada "__baru__" dan "__panggilan__"
Dalam metaclass, "__new__" akan dilaksanakan apabila anda mentakrifkan kelas Ia hanya akan dilaksanakan sekali Jika dua kelas menggunakan metaclass ini, OK, ia akan dilaksanakan dua kali
Dan __call__ akan dipanggil setiap kali anda membuat instantiat, sebenarnya, ia adalah sama dengan Foo.__new__, yang bermaksud jika Foo anda mentakrifkan __new__, __call__ dalam metaclass tidak akan Laksanakan
"__baru__" kelas meta boleh menukar jenis yang anda takrifkan di sini sebagai senarai
Sangat sukar untuk menulis begitu banyak. Terdapat sangat sedikit orang yang dapat memahami metaclass dengan betul. Saya tidak tahu bagaimana untuk berterima kasih kepada saya kerana bertanyakan soalan itu
Ini bukan masalah metaclass yang menjejaskan keutamaan new dan call, tetapi __new__ metaclass itu hanya akan dipanggil sekali apabila mencipta kelas. Dan __new__ ini digunakan untuk mencipta kelas kami, seperti dalam soalan anda. Bilakah ia dicipta? Apabila jurubahasa mentafsir kelas Foo, ia akan mencari atribut __metaclass__ dalam definisi kelas, dan jika ia ditemui, gunakannya untuk mencipta kelas. Jika tidak ditemui, jenis terbina dalam akan digunakan untuk mencipta kelas. Mengapa tidak memanggilnya semula? Kerana metaclass telah mencipta kelas kami, kami tidak boleh mencipta semula kelas setiap kali Foo() dipanggil. Ia juga boleh dilihat daripada output anda bahawa foo2 = Foo() tidak mengeluarkan __new__. Kerana pada masa ini kelas telah dicipta oleh metaclass, iaitu,
Singleton
, anda boleh mula menggunakannya secara langsung. Ia tidak berbeza dengan kelas yang biasa kita gunakan, jadi setiap kali ia dicipta, objek baru dicipta. Dan mengapa menggunakan __call__?Kerana Foo ialah kelas yang dicipta oleh metaclass Singleton, anda boleh menganggap Foo sebagai objek contoh Singleton. Jadi __call__ akan dipanggil setiap kali Foo() dipanggil. Dalam __call__ kita mendapat objek contoh yang telah dibuat. Bukankah ia hanya singleton? .
Mari jelaskan secara terperinci melalui kod
Selepas berjalan, anda akan mendapati bahawa cls dalam fungsi __call__ ialah kelas yang dicipta dengan memanggil __new__ untuk kali pertama dan satu-satunya dalam metaclass, iaitu Foo, dan cls._instance ialah objek contoh Foo kami. Setiap kali Foo() dipanggil, objek contoh yang sama diperoleh. Metaclass adalah, selepas semua, kelas yang mencipta kelas. Setelah dibuat, kelas itu tidak berbeza daripada kelas yang biasa anda tentukan.