Inheritance — Python

Inheritance (Pewarisan) Inheritance memungkinkan class baru mewarisi properti dan method dari class yang sudah ada. Basic Inheritance class Hewan: def…

Inheritance (pewarisan) membuat class baru dari class yang sudah ada: class baru mewarisi semua atribut dan method induknya, lalu boleh menambah atau mengganti sebagian. Bayangin Pak Darto mau bikin kartu khusus minuman. Dia gak merancang kartu dari nol. Dia ambil blanko kartu menu yang lama (nama, harga), lalu menambah satu kolom: "pakai es?". Semua yang ada di kartu menu tetap ada di kartu minuman.

🧪 Tebakan cepat: MenuMinuman punya __init__ sendiri yang cuma menulis self.es = es, tanpa super().__init__(...). Setelah teh = MenuMinuman("teh manis", 5000, es=True), apa hasil print(teh.nama): teh manis, atau error? Tebak dulu, jawabannya ada di bagian "super(): memanggil versi induk".

Class turunan

Kita pakai class Menu dari pelajaran sebelumnya:

class Menu:
    def __init__(self, nama, harga):
        self.nama = nama
        self.harga = harga

    def total(self, jumlah):
        return self.harga * jumlah

    def __str__(self):
        return f"{self.nama} ({self.harga})"

class MenuMinuman(Menu):
    pass

teh = MenuMinuman("teh manis", 5000)
print(teh)            # teh manis (5000)
print(teh.total(4))   # 20000

Menambah dan mengganti method

Anak boleh menulis method dengan nama yang sama seperti milik induknya. Untuk object anak, method itu menggantikan milik induk. Ini disebut override. Di warung Pak Darto, minuman pakai es lebih mahal Rp2.000 per gelas:

class MenuMinuman(Menu):
    def __init__(self, nama, harga, es=False):
        super().__init__(nama, harga)
        self.es = es

    def total(self, jumlah):
        hasil = super().total(jumlah)
        if self.es:
            hasil = hasil + 2000 * jumlah
        return hasil

teh = MenuMinuman("teh manis", 5000, es=True)
kopi = MenuMinuman("kopi susu", 15000)
roti = Menu("roti bakar", 12000)
print(teh.total(4))    # 28000
print(kopi.total(3))   # 45000
print(roti.total(2))   # 24000
print(teh)             # teh manis (5000)
Panggilan total milik Hitungan Hasil
teh.total(4) MenuMinuman 5000 × 4 = 20000, ditambah es 2000 × 4 = 8000 28000
kopi.total(3) MenuMinuman 15000 × 3, es bernilai False 45000
roti.total(2) Menu 12000 × 2 24000

super(): memanggil versi induk

super() memberi akses ke method milik induk. Ada dua pemakaian di kode tadi:

Kalau anak punya __init__ sendiri, __init__ milik induk gak jalan otomatis. Tanpa baris super().__init__(nama, harga), object teh gak pernah dapat nama dan harga:

Traceback (most recent call last):
  File "/home/darto/warung.py", line 17, in <module>
    print(teh.nama)
          ^^^^^^^^
AttributeError: 'MenuMinuman' object has no attribute 'nama'

Jadi hasilnya error, bukan teh manis. Itu jawaban tebakannya.

isinstance dan urutan pencarian (MRO)

print(isinstance(teh, MenuMinuman))   # True
print(isinstance(teh, Menu))          # True
print(isinstance(roti, MenuMinuman))  # False
print(type(teh) == Menu)              # False
print(MenuMinuman.__mro__)

Baris terakhir mencetak:

(<class '__main__.MenuMinuman'>, <class '__main__.Menu'>, <class 'object'>)

📌 Induk lebih dari satu

Class boleh punya beberapa induk: class D(B, C):. MRO-nya dibaca dari kiri ke kanan, dan induk bersama (A) baru dicek setelah semua anaknya:

class A:
    def hai(self):
        return "A"

class B(A):
    def hai(self):
        return "B"

class C(A):
    def hai(self):
        return "C"

class D(B, C):
    pass

print(D().hai())                          # B
print([k.__name__ for k in D.__mro__])    # ['D', 'B', 'C', 'A', 'object']

D gak punya hai, jadi Python mencari di B dulu dan berhenti di sana. Pola ini jarang dibutuhkan pemula. Satu induk sudah cukup untuk hampir semua kasus.

⚠️ Jebakan yang sering ketemu

TL;DR: class MenuMinuman(Menu): membuat class anak yang mewarisi semua atribut dan method Menu. Method dengan nama yang sama di anak meng-override milik induk, untuk object anak saja. super() memanggil versi induk: super().__init__(nama, harga) menjalankan constructor induk (tanpa self), dan super().total(jumlah) memakai rumus induk. __init__ anak gak menjalankan milik induk otomatis, jadi tanpa super().__init__ muncul AttributeError. isinstance(teh, Menu) bernilai True untuk turunan juga, beda dengan type(teh) == Menu. Python mencari method menurut MRO: class object dulu, lalu induknya, sampai object.

Yang akan kamu pelajari