Sejauh ini setiap class kita hanya mewarisi dari satu induk. Python sebenarnya mengizinkan lebih: sebuah class bisa mewarisi dua, tiga, atau lebih class sekaligus — fitur bernama multiple inheritance. Sebagian bahasa OOP (Java, misalnya) melarangnya untuk class biasa; Python justru menjadikannya fondasi bagi pola desain yang sangat produktif, yaitu mixin. Kuatnya besar, tetapi dayanya juga bisa berbahaya: begitu dua induk membawa method bernama sama, muncullah pertanyaan “versi mana yang menang?” Chapter ini memperkenalkan sintaksnya, bentuk paling terkenal dari konfliknya (diamond problem), dan cara pemakaian yang aman lewat mixin.

Sintaks Dasar #

Daftar induk ditulis di dalam tanda kurung, dipisahkan koma, dan dibaca dari kiri ke kanan:

python
class Penulis:
    def menulis(self):
        return "menulis naskah"

class Pengajar:
    def mengajar(self):
        return "mengajar kelas"

class PenulisPengajar(Penulis, Pengajar):
    pass

budi = PenulisPengajar()

print(budi.menulis())
print(budi.mengajar())

Output yang Dihasilkan:

text
menulis naskah
mengajar kelas

Object budi mewarisi method dari kedua induknya: menulis() berasal dari Penulis, mengajar() dari Pengajar. Selama kedua induk tidak bertabrakan nama, semuanya berjalan mulus — class gabungan ini memang benar-benar gabungan dari dua sumber.

Diamond Problem #

Kesulitan muncul ketika jalur pewarisan membentuk belah ketupat: dua induk yang sama-sama turunan dari satu kakek. Bentuk ini disebut diamond problem — masalah klasik semua bahasa yang mengizinkan multiple inheritance:

D mewarisi B dan C; keduanya mewarisi A. Method sapa() ada di A, di-override di C, dan tidak disentuh di B. Dari mana D mendapatkan sapa()?

python
class A:
    def sapa(self):
        return "sapa dari A"

class B(A):
    pass

class C(A):
    def sapa(self):
        return "sapa dari C"

class D(B, C):
    pass

d = D()

print(d.sapa())

Output yang Dihasilkan:

text
sapa dari C

Jawabannya: sapa dari C. Banyak yang menduga A — karena B (induk pertama D) langsung di bawah A. Ternyata tidak: Python memakai jalur pencarian D → B → C → A, sehingga C ditemukan lebih dulu daripada A. Jalur pasti inilah yang dibedah pada Chapter Method Resolution Order — dan jalur tersebut juga yang membuat fungsi super() berperilaku mengejutkan di Chapter super().

Pola Mixin #

Pemakaian multiple inheritance yang paling sehat di ekosistem Python adalah mixin: class kecil yang membawa satu kemampuan spesifik, tidak dimaksudkan berdiri sendiri, lalu “dilewarkan” ke class lain. Contoh klasiknya, mixin pencatat log:

python
class LogMixin:
    def log(self, pesan):
        print(f"[LOG] {self.__class__.__name__}: {pesan}")

class Buku(LogMixin):
    def __init__(self, judul):
        self.judul = judul

    def pinjam(self, peminjam):
        self.log(f"'{self.judul}' dipinjam oleh {peminjam}")
        return f"{self.judul} dipinjam oleh {peminjam}"

class Anggota(LogMixin):
    def __init__(self, nama):
        self.nama = nama

    def daftar(self):
        self.log(f"anggota baru terdaftar: {self.nama}")
        return f"Anggota {self.nama} terdaftar"

buku = Buku("Laskar Pelangi")
anggota = Anggota("Budi")

print(buku.pinjam("Budi"))
print(anggota.daftar())

Output yang Dihasilkan:

text
[LOG] Buku: 'Laskar Pelangi' dipinjam oleh Budi
Laskar Pelangi dipinjam oleh Budi
[LOG] Anggota: anggota baru terdaftar: Budi
Anggota Budi terdaftar

Mari kita telaah cara kerjanya:

  1. Baris 1 (class LogMixin:): mixin hanya berisi satu method, tanpa __init__ dan tanpa data. Nama class kebiasaannya diakhiri Mixin agar niatnya terbaca.
  2. Baris 3 (self.__class__.__name__): attribute ini membaca nama class milik object pemanggil, sehingga satu mixin yang sama mencetak Buku untuk buku dan Anggota untuk anggota.
  3. Baris 5 (class Buku(LogMixin):): Buku melewatkan mixin sebagai induk — dan seketika punya kemampuan log() tanpa menulis ulang apa pun.
  4. Method pinjam() dan daftar() keduanya memanggil self.log(...) — kode pencatatan berada di satu tempat, dipakai dua class berbeda.

Bandingkan dengan alternatifnya: menyalin method log() ke tiap class (duplikasi), atau membuat Buku dan Anggota mewarisi satu induk raksasa bernama PencatatLog (relasi is-a yang tidak jujur — buku bukanlah pencatat log).

Peringatan Desain #

Aturan praktis yang dipakai komunitas Python: pewarisan ganda hanya untuk mixin kecil dan berfokus — bukan untuk menggabungkan dua class utuh yang masing-masing membawa banyak attribute dan method. Untuk relasi has-a antara class utuh, composition pada Chapter Composition tetap pilihan pertama. Dengan aturan main itu, kita siap membedah mesin yang menjawab “method mana yang menang”: Method Resolution Order.