Method Resolution Order
MRO (Method Resolution Order) adalah aturan yang digunakan Python untuk menentukan urutan pencarian attribute dan method pada sebuah class atau object.
MRO menjadi sangat penting ketika kita menggunakan multiple inheritance, karena sebuah class dapat memiliki lebih dari satu parent class.
Dengan MRO, Python memiliki aturan yang jelas untuk menentukan class mana yang harus diperiksa terlebih dahulu ketika mencari attribute atau method.
Mengapa MRO Dibutuhkan?
Pada inheritance sederhana, struktur class biasanya mudah dipahami:
A
│
└── B
Ketika Python mencari attribute atau method pada object B, Python dapat mencari dari:
B → A → object
Namun, pada multiple inheritance, strukturnya dapat menjadi lebih kompleks:
A
/ \
B C
\ /
D
Class D memiliki dua parent:
class D(B, C):
pass
Jika B dan C memiliki method atau attribute dengan nama yang sama, Python harus menentukan mana yang digunakan terlebih dahulu.
MRO menentukan urutan tersebut.
Contoh Hirarki MRO
Perhatikan contoh berikut:
class A:
num = 10
class B(A):
pass
class C(A):
num = 1
class D(B, C):
pass
Struktur inheritance tersebut adalah:
A
/ \
B C
\ /
D
Class D mewarisi dari:
B
C
Sedangkan B dan C sama-sama mewarisi A.
Apa yang Terjadi Ketika Memanggil D.num?
Sekarang kita menjalankan:
print(D.num)
Python harus mencari attribute num.
MRO menentukan urutan pencarian:
D
↓
B
↓
C
↓
A
↓
object
Python pertama-tama memeriksa D.
D tidak memiliki num.
Kemudian Python memeriksa B.
B juga tidak memiliki num.
Selanjutnya Python memeriksa C.
C memiliki:
num = 1
Maka pencarian berhenti.
Hasilnya:
1
Mengapa Bukan 10?
Class A memiliki:
num = 10
Sedangkan class C memiliki:
num = 1
Meskipun A juga memiliki num, Python menemukan num milik C terlebih dahulu berdasarkan MRO.
Urutannya:
D → B → C → A → object
Karena C diperiksa sebelum A, maka:
D.num
menghasilkan:
1
Melihat MRO dengan .mro()
Python menyediakan method mro() untuk melihat urutan MRO sebuah class.
Contoh:
print(D.mro())
Hasilnya:
[
<class '__main__.D'>,
<class '__main__.B'>,
<class '__main__.C'>,
<class '__main__.A'>,
<class 'object'>
]
Jika disederhanakan:
D
↓
B
↓
C
↓
A
↓
object
Urutan tersebut menunjukkan bagaimana Python mencari attribute dan method.
Melihat MRO dengan __mro__
Selain menggunakan:
D.mro()
kita juga dapat menggunakan attribute:
D.__mro__
Contoh:
print(D.__mro__)
Hasilnya akan menunjukkan urutan class yang sama.
Kedua pendekatan tersebut dapat digunakan untuk melihat MRO:
D.mro()
dan:
D.__mro__
MRO dan Pencarian Method
MRO tidak hanya digunakan untuk mencari attribute.
MRO juga digunakan ketika Python mencari method.
Misalnya:
class A:
def hello(self):
print("A")
class B(A):
def hello(self):
print("B")
class C(A):
def hello(self):
print("C")
class D(B, C):
pass
Kemudian:
d = D()
d.hello()
Python akan mengikuti MRO.
Urutannya:
D → B → C → A → object
Karena B memiliki method hello(), Python akan menggunakan method tersebut.
Output:
B
Urutan Pewarisan Berpengaruh pada MRO
Perhatikan:
class D(B, C):
pass
Urutan parent ditulis:
B → C
Jika kita mengubahnya menjadi:
class D(C, B):
pass
urutan MRO juga dapat berubah.
Secara konsep:
D → C → B → A → object
Oleh karena itu, urutan parent class dalam multiple inheritance sangat penting.
C3 Linearization
Python menggunakan algoritma C3 Linearization untuk menentukan MRO.
C3 Linearization memastikan bahwa urutan inheritance tetap konsisten dan memenuhi aturan tertentu.
Salah satu tujuan pentingnya adalah menjaga:
- Child class diperiksa sebelum parent class.
- Urutan parent class tetap dihormati.
- Hubungan inheritance tetap konsisten.
- Ambiguitas dalam multiple inheritance dapat dihindari.
Untuk tahap awal pembelajaran, kita tidak perlu menghitung algoritma C3 Linearization secara manual.
Yang penting dipahami adalah bahwa Python menggunakan mekanisme tersebut untuk menentukan MRO.
MRO dan Diamond Problem
MRO sangat berkaitan dengan Diamond Problem.
Contoh struktur diamond:
A
/ \
B C
\ /
D
Dalam struktur tersebut:
BmewarisiA.CmewarisiA.DmewarisiBdanC.
Masalahnya adalah ketika beberapa class memiliki method atau attribute dengan nama yang sama.
Misalnya:
class A:
def hello(self):
print("A")
class B(A):
def hello(self):
print("B")
class C(A):
def hello(self):
print("C")
class D(B, C):
pass
Ketika:
d = D()
d.hello()
Python harus menentukan apakah menggunakan:
B.hello()
atau:
C.hello()
MRO memberikan aturan yang konsisten untuk menentukan jawabannya.
MRO pada Contoh Diamond
Untuk:
class D(B, C):
pass
MRO-nya adalah:
D
↓
B
↓
C
↓
A
↓
object
Karena B berada sebelum C, maka method hello() milik B akan ditemukan terlebih dahulu.
Output:
B
MRO dan Base Class object
Seperti yang telah dipelajari sebelumnya, semua class Python pada akhirnya memiliki hubungan dengan base class:
object
Karena itu, MRO biasanya berakhir pada:
object
Contohnya:
D
↓
B
↓
C
↓
A
↓
object
Jika attribute atau method tidak ditemukan pada seluruh class sebelumnya, Python akan terus mencari hingga object.
MRO dalam Multiple Inheritance
Pada multiple inheritance:
class HybridBorg(Wizard, Archer):
pass
Python harus menentukan urutan pencarian.
Kita dapat melihatnya dengan:
print(HybridBorg.mro())
atau:
print(HybridBorg.__mro__)
Hal ini sangat berguna ketika kita ingin mengetahui dari mana sebuah method atau attribute berasal.
Mengapa MRO Penting?
MRO penting karena memungkinkan Python menentukan perilaku object secara konsisten.
Tanpa MRO, multiple inheritance dapat menghasilkan kebingungan ketika beberapa parent class memiliki method atau attribute yang sama.
Dengan MRO, Python memiliki aturan yang jelas untuk menentukan:
Class mana yang diperiksa terlebih dahulu?
Kemudian:
Jika tidak ditemukan, class mana yang diperiksa berikutnya?
Cara Praktis Memeriksa MRO
Ketika menggunakan multiple inheritance dan mengalami perilaku yang tidak sesuai harapan, kita dapat memeriksa MRO menggunakan:
ClassName.mro()
Contohnya:
print(D.mro())
atau:
print(D.__mro__)
Dengan melihat hasil tersebut, kita dapat mengetahui urutan pencarian Python.
Kesimpulan
MRO (Method Resolution Order) adalah aturan yang menentukan urutan Python dalam mencari attribute dan method pada inheritance hierarchy.
MRO sangat penting pada multiple inheritance.
Contoh:
class D(B, C):
pass
Python dapat memiliki MRO:
D → B → C → A → object
Kita dapat melihat MRO menggunakan:
D.mro()
atau:
D.__mro__
Python menggunakan C3 Linearization untuk menentukan MRO.
MRO juga membantu mengatasi ambiguitas pada Diamond Problem sehingga pencarian method dan attribute tetap memiliki urutan yang konsisten.
Setelah memahami MRO, konsep berikutnya yang penting untuk dipelajari adalah bagaimana super() bekerja berdasarkan Method Resolution Order, terutama pada multiple inheritance.