Dalam buku Python in a Nutshell (Edisi ke-2) terdapat contoh yang menggunakan
kelas gaya lama untuk mendemonstrasikan bagaimana metode diselesaikan dalam urutan resolusi klasik dan
apa bedanya dengan orde baru.
Saya mencoba contoh yang sama dengan menulis ulang contoh dalam gaya baru tetapi hasilnya tidak berbeda dengan apa yang diperoleh dengan kelas gaya lama. Versi python yang saya gunakan untuk menjalankan contoh adalah 2.5.2. Berikut contohnya:
class Base1(object):
def amethod(self): print "Base1"
class Base2(Base1):
pass
class Base3(object):
def amethod(self): print "Base3"
class Derived(Base2,Base3):
pass
instance = Derived()
instance.amethod()
print Derived.__mro__
Panggilan tersebut instance.amethod()
dicetak Base1
, tetapi sesuai pemahaman saya tentang MRO dengan gaya kelas baru, outputnya seharusnya Base3
. Panggilan Derived.__mro__
mencetak:
(<class '__main__.Derived'>, <class '__main__.Base2'>, <class '__main__.Base1'>, <class '__main__.Base3'>, <type 'object'>)
Saya tidak yakin apakah pemahaman saya tentang MRO dengan kelas gaya baru tidak benar atau saya melakukan kesalahan konyol yang tidak dapat saya deteksi. Tolong bantu saya untuk lebih memahami MRO.
sumber
Urutan resolusi metode Python sebenarnya lebih kompleks dari sekedar memahami pola berlian. Untuk benar-benar memahaminya, lihat linierisasi C3 . Saya merasa sangat membantu untuk menggunakan pernyataan cetak saat memperluas metode untuk melacak pesanan. Misalnya, menurut Anda apa hasil dari pola ini? (Catatan: 'X' dianggap dua tepi bersilangan, bukan simpul dan ^ menandakan metode yang memanggil super ())
class G(): def m(self): print("G") class F(G): def m(self): print("F") super().m() class E(G): def m(self): print("E") super().m() class D(G): def m(self): print("D") super().m() class C(E): def m(self): print("C") super().m() class B(D, E, F): def m(self): print("B") super().m() class A(B, C): def m(self): print("A") super().m() # A^ # / \ # B^ C^ # /| X # D^ E^ F^ # \ | / # G
Apakah Anda mendapatkan ABDCEFG?
Setelah banyak trial-error, saya mendapatkan interpretasi teori grafik informal linierisasi C3 sebagai berikut: (Seseorang tolong beri tahu saya jika ini salah.)
Pertimbangkan contoh ini:
class I(G): def m(self): print("I") super().m() class H(): def m(self): print("H") class G(H): def m(self): print("G") super().m() class F(H): def m(self): print("F") super().m() class E(H): def m(self): print("E") super().m() class D(F): def m(self): print("D") super().m() class C(E, F, G): def m(self): print("C") super().m() class B(): def m(self): print("B") super().m() class A(B, C, D): def m(self): print("A") super().m() # Algorithm: # 1. Build an inheritance graph such that the children point at the parents (you'll have to imagine the arrows are there) and # keeping the correct left to right order. (I've marked methods that call super with ^) # A^ # / | \ # / | \ # B^ C^ D^ I^ # / | \ / / # / | X / # / |/ \ / # E^ F^ G^ # \ | / # \ | / # H # (In this example, A is a child of B, so imagine an edge going FROM A TO B) # 2. Remove all classes that aren't eventually inherited by A # A^ # / | \ # / | \ # B^ C^ D^ # / | \ / # / | X # / |/ \ # E^ F^ G^ # \ | / # \ | / # H # 3. For each level of the graph from bottom to top # For each node in the level from right to left # Remove all of the edges coming into the node except for the right-most one # Remove all of the edges going out of the node except for the left-most one # Level {H} # # A^ # / | \ # / | \ # B^ C^ D^ # / | \ / # / | X # / |/ \ # E^ F^ G^ # | # | # H # Level {G F E} # # A^ # / | \ # / | \ # B^ C^ D^ # | \ / # | X # | | \ # E^F^ G^ # | # | # H # Level {D C B} # # A^ # /| \ # / | \ # B^ C^ D^ # | | # | | # | | # E^ F^ G^ # | # | # H # Level {A} # # A^ # | # | # B^ C^ D^ # | | # | | # | | # E^ F^ G^ # | # | # H # The resolution order can now be determined by reading from top to bottom, left to right. A B C E D F G H x = A() x.m()
sumber
super
memiliki argumen yang dibutuhkan.Hasil yang Anda dapatkan benar. Coba ubah kelas dasar
Base3
menjadiBase1
dan bandingkan dengan hierarki yang sama untuk kelas klasik:class Base1(object): def amethod(self): print "Base1" class Base2(Base1): pass class Base3(Base1): def amethod(self): print "Base3" class Derived(Base2,Base3): pass instance = Derived() instance.amethod() class Base1: def amethod(self): print "Base1" class Base2(Base1): pass class Base3(Base1): def amethod(self): print "Base3" class Derived(Base2,Base3): pass instance = Derived() instance.amethod()
Sekarang outputnya:
Baca penjelasan ini untuk informasi lebih lanjut.
sumber
Anda melihat perilaku itu karena resolusi metode adalah yang mengutamakan kedalaman, bukan yang pertama luas. Seperti warisan Dervied
Begitu
instance.amethod()
amethod
, sehingga dipanggil.Ini tercermin dalam
Derived.__mro__
. Cukup ulangiDerived.__mro__
dan hentikan saat Anda menemukan metode yang dicari.sumber