Dalam Python, apabila mentakrifkan kelas, anda boleh menentukan kelas induknya. Subkelas mewarisi semua sifat dan kaedah kelas induknya dan boleh menambah sifat dan kaedah uniknya sendiri.
Walau bagaimanapun, jika kelas mempunyai berbilang kelas induk langsung, mungkin terdapat sifat dan kaedah dengan nama yang sama antara kelas induk ini. Untuk memanggil sifat dan kaedah ini dengan betul, Python menggunakan algoritma yang dipanggil "Perintah Resolusi Kaedah" (Perintah Resolusi Kaedah, MRO) untuk menentukan susunan carian sifat dan kaedah.
Dalam Python 2.x, MRO dilaksanakan menggunakan algoritma carian pertama mendalam (DFS). Terdapat beberapa masalah dengan algoritma ini yang menyebabkan urutan panggilan kaedah tidak dihuraikan dengan betul dalam beberapa kes. Contohnya:
class A: def foo(self): print("A.foo") class B(A): pass class C(A): def foo(self): print("C.foo") class D(B, C): pass d = D() d.foo() # 输出"A.foo",而不是"C.foo"
Dalam kod di atas, kelas D mewarisi kelas B dan kelas C, dan kelas C mengatasi kaedah foo() kelas A. Oleh itu, apabila memanggil kaedah foo() objek d, secara teorinya kaedah foo() dalam kelas C harus dipanggil dahulu. Walau bagaimanapun, memandangkan Python 2.x menggunakan algoritma DFS, ia akan merentasi kelas B dahulu, kemudian kelas C, dan akhirnya kelas A. Oleh itu, kaedah foo() dalam kelas A akhirnya dipanggil, bukan kaedah foo() dalam kelas C.
Untuk menyelesaikan masalah ini, Python 2.3 memperkenalkan algoritma C3, yang menggunakan algoritma pengisihan topologi untuk mengira senarai MRO bagi memastikan ketepatan semasa memanggil kaedah. Prinsip asas algoritma C3 adalah seperti berikut:
Senarai MRO kelas gaya baharu (iaitu, kelas yang secara eksplisit mewarisi objek atau mewarisi objek secara tersirat) dikira mengikut algoritma carian luas-pertama (BFS).
Untuk setiap kelas, senarai MROnya hendaklah memenuhi tiga syarat berikut:
Senarai MRO subkelas hendaklah diberi kedudukan Pada hadapan senarai MRO kelas induk.
Jika dua kelas induk muncul dalam senarai MRO kelas anak, susunan relatif mereka dalam senarai adalah sama dengan penampilan mereka dalam kelas induk terdekat kelas anak pesanan adalah sama.
Sesuatu kelas tidak boleh muncul lebih daripada dua kali dalam senarai MROnya.
Algoritma ini boleh mengendalikan situasi dalam contoh kod di atas dengan betul, dengan itu memastikan ketepatan semasa memanggil kaedah.
Dalam Python 3, anda boleh melihat senarai MRO kelas melalui atribut __mro__
. Contohnya:
class A: def foo(self): print("A.foo") class B(A): pass class C(A): def foo(self): print("C.foo") class D(B, C): pass print(D.__mro__)
Hasil output ialah:
(
, , < ;kelas '__main__.C'>, , )
di mana, <class '__main__.D'>
mewakili kelas D itu sendiri, <class '__main__.B'>
dan <class '__main__.C'>
masing-masing mewakili kelas induk B dan C kelas D, <class '__main__.A'>
mewakili kelas induk biasa A kelas B dan C, dan <class 'object'>
mewakili kelas asas semua kelas gaya baharu . Susunan senarai ini ialah susunan sifat dan kaedah dicari apabila Python sedang berjalan.
Atas ialah kandungan terperinci Bagaimanakah subkelas python menggunakan MRO dalam pelbagai warisan?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!