Pendahuluan — satu pemanggilan, banyak bentuk
Di Inheritance & super() (#44) kamu sudah punya Buku dan Ebook dengan info() yang berbeda. Hari ini kita manfaatkan itu: satu loop memanggil item.info(), tiap object merespons sesuai bentuknya.
Polymorphism (banyak bentuk) = object berbeda merespons pesan/method yang sama dengan cara masing-masing. Di Python, ini sering tampak sederhana: “kalau object punya info(), panggil saja.”
Prasyarat: Selesai Inheritance (#44) (nyaman dengan
Ebook(Buku),super(), override). Fondasi: Encapsulation (#43) · Attribute (#42) · Class & Object (#41) · Mengenal OOP (#40).
Kenapa polymorphism terasa “ajaib”?
Tanpa polymorphism, katalog campuran cepat jadi hutan if/isinstance. Dengan polymorphism:
- Kode pemanggil tetap pendek:
for item in koleksi: print(item.info()) - Perilaku spesifik tinggal di class masing-masing (override)
- Menambah tipe baru (mis.
Audiobook) sering tidak memaksa ubah loop
Intinya: satu antarmuka, banyak implementasi.
Siapkan Buku, Ebook, Audiobook
Versi ringkas lanjutan Inheritance (#44) — fokus ke info() yang berbeda per class:
class Buku:
def __init__(self, judul, penulis, tahun, stok=1):
self.judul = judul
self.penulis = penulis
self.tahun = tahun
self.stok = stok
def info(self):
return f"{self.judul} · {self.penulis} ({self.tahun}) · stok {self.stok}"
class Ebook(Buku):
def __init__(self, judul, penulis, tahun, stok=1, format_file="epub", ukuran_mb=1.0):
super().__init__(judul, penulis, tahun, stok)
self.format_file = format_file
self.ukuran_mb = ukuran_mb
def info(self):
return f"{super().info()} · {self.format_file.upper()} ({self.ukuran_mb} MB)"
class Audiobook(Buku):
def __init__(self, judul, penulis, tahun, stok=1, durasi_menit=60):
super().__init__(judul, penulis, tahun, stok)
self.durasi_menit = durasi_menit
def info(self):
return f"{super().info()} · audio {self.durasi_menit} menit"
b = Buku("ESP32 Praktis", "Budi", 2023)
e = Ebook("Belajar Python", "Sari", 2024, format_file="pdf", ukuran_mb=4.5)
a = Audiobook("Cerita Sensor", "Ani", 2025, durasi_menit=90)
print(b.info())
print(e.info())
print(a.info())
Satu loop untuk semua — inti polymorphism
Masukkan object berbeda ke satu list, lalu panggil method yang sama:
class Buku:
def __init__(self, judul, penulis, tahun, stok=1):
self.judul = judul
self.penulis = penulis
self.tahun = tahun
self.stok = stok
def info(self):
return f"{self.judul} · {self.penulis} ({self.tahun}) · stok {self.stok}"
class Ebook(Buku):
def __init__(self, judul, penulis, tahun, stok=1, format_file="epub", ukuran_mb=1.0):
super().__init__(judul, penulis, tahun, stok)
self.format_file = format_file
self.ukuran_mb = ukuran_mb
def info(self):
return f"{super().info()} · {self.format_file.upper()} ({self.ukuran_mb} MB)"
class Audiobook(Buku):
def __init__(self, judul, penulis, tahun, stok=1, durasi_menit=60):
super().__init__(judul, penulis, tahun, stok)
self.durasi_menit = durasi_menit
def info(self):
return f"{super().info()} · audio {self.durasi_menit} menit"
koleksi = [
Buku("ESP32 Praktis", "Budi", 2023),
Ebook("Belajar Python", "Sari", 2024, format_file="pdf", ukuran_mb=4.5),
Audiobook("Cerita Sensor", "Ani", 2025, durasi_menit=90),
]
for item in koleksi:
print(item.info()) # tiap class menjawab dengan caranya sendiri
Loop tidak perlu tahu “ini Ebook atau Audiobook”. Yang penting: tiap item paham cara menjawab info(). Python mencari method di tipe object yang sebenarnya — object Ebook menjalankan Ebook.info, bukan versi induk.
Output kurang lebih:
ESP32 Praktis · Budi (2023) · stok 1
Belajar Python · Sari (2024) · stok 1 · PDF (4.5 MB)
Cerita Sensor · Ani (2025) · stok 1 · audio 90 menit
info(), tiga jawaban berbeda — itu polymorphism di kerja sehari-hari.Duck typing — “kalau bisa quack…”
Python tidak selalu menuntut warisan formal. Object di luar pohon Buku pun bisa ikut loop jika punya method yang dibutuhkan:
class Buku:
def __init__(self, judul):
self.judul = judul
def info(self):
return f"Buku: {self.judul}"
class KatalogEntry:
"""Bukan subclass Buku — tapi punya info()."""
def __init__(self, judul, sumber):
self.judul = judul
self.sumber = sumber
def info(self):
return f"Entri katalog: {self.judul} ({self.sumber})"
koleksi = [
Buku("ESP32 Praktis"),
KatalogEntry("Datasheet DHT22", "vendor"),
]
for item in koleksi:
print(item.info()) # jalan — keduanya “bisa di-info()”
Ini sering disebut duck typing: yang diuji kemampuan (info()), bukan silsilah class. Inheritance tetap berguna untuk berbagi state/perilaku; duck typing berguna saat kontrak method-nya kecil dan jelas.
Risikonya: object yang “kelihatan cocok” tapi tanpa method yang diharapkan gagal saat runtime:
class Buku:
def __init__(self, judul):
self.judul = judul
def info(self):
return f"Buku: {self.judul}"
koleksi = [Buku("ESP32 Praktis"), {"judul": "bukan object"}]
# for item in koleksi:
# print(item.info()) # AttributeError: 'dict' object has no attribute 'info'
print(koleksi[0].info())
Ingat: duck typing fleksibel, tapi error muncul saat runtime jika method hilang (
AttributeError). Untuk kontrak ketat antar banyak class, lihat Abstraction & ABC (#46).
isinstance — kapan boleh, kapan berlebihan
isinstance berguna untuk pengecualian, bukan sebagai pengganti polymorphism. Bandingkan SALAH vs BENAR:
class Buku:
def __init__(self, judul):
self.judul = judul
def info(self):
return f"Buku: {self.judul}"
class Ebook(Buku):
def __init__(self, judul, format_file="pdf"):
super().__init__(judul)
self.format_file = format_file
def info(self):
return f"Ebook: {self.judul} · {self.format_file}"
def unduh(self):
return f"unduh {self.judul}.{self.format_file}"
# SALAH — hutan isinstance menggantikan method bersama
# (urutan Ebook→Buku di sini sudah “aman”; yang salah adalah pola hutannya)
def cetak_salah(koleksi):
for item in koleksi:
if isinstance(item, Ebook):
print(f"Ebook: {item.judul} · {item.format_file}")
elif isinstance(item, Buku):
print(f"Buku: {item.judul}")
else:
print("tipe tidak dikenal")
# BENAR — andalkan info(); isinstance hanya untuk aksi khusus
def cetak_benar(koleksi):
for item in koleksi:
print(item.info())
if isinstance(item, Ebook):
print(" →", item.unduh()) # hanya Ebook yang punya unduh()
koleksi = [Buku("ESP32 Praktis"), Ebook("Belajar Python", "pdf")]
cetak_benar(koleksi)
# cetak_salah(koleksi) # anti-pola — jangan dijadikan kebiasaan
Pakai isinstance saat ada kemampuan yang memang hanya milik sebagian tipe (mis. unduh() di ebook). Jangan pakai untuk meniru seluruh info() yang seharusnya di-override.
Jebakan urutan: karena isinstance(ebook, Buku) juga True (lihat Inheritance (#44)), rantai yang cek induk dulu menelan ebook:
class Buku:
pass
class Ebook(Buku):
pass
e = Ebook()
if isinstance(e, Buku):
print("cabang Buku") # kena — Ebook juga Buku
elif isinstance(e, Ebook):
print("cabang Ebook") # tidak pernah tercapai
Output: cabang Buku. Kalau terpaksa menulis rantai, cek tipe anak dulu — atau lebih baik, andalkan method bersama seperti di cetak_benar. Catatan: di contoh cetak_salah urutan Ebook→Buku sudah tepat; yang dilarang adalah mengganti info() dengan hutan isinstance.
Pola Dasar — merancang polymorphism
-
1
Samakan nama method Mis. semua item katalog punya
info()— antarmuka bersama. -
2
Override di anak (bila warisan) Detail spesifik tinggal di class; pemanggil tidak perlu tahu tipenya.
-
3
Loop lewat antarmuka
for item in koleksi: item.info()— bukan rantaiisinstance. -
4
isinstance hanya pengecualian Untuk aksi yang benar-benar khas satu tipe (unduh, play, dll.).
-
5
Uji tipe baru Tambah class baru ke list — loop lama sebaiknya tetap jalan tanpa diubah.
Kode lengkap — salin & jalankan
Simpan sebagai koleksi_polimorfik.py, lalu python koleksi_polimorfik.py:
class Buku:
def __init__(self, judul, penulis, tahun, stok=1):
self.judul = judul
self.penulis = penulis
self.tahun = tahun
self.stok = stok
def info(self):
return f"{self.judul} · {self.penulis} ({self.tahun}) · stok {self.stok}"
class Ebook(Buku):
def __init__(self, judul, penulis, tahun, stok=1, format_file="epub", ukuran_mb=1.0):
super().__init__(judul, penulis, tahun, stok)
self.format_file = format_file
self.ukuran_mb = ukuran_mb
def info(self):
return f"{super().info()} · {self.format_file.upper()} ({self.ukuran_mb} MB)"
def unduh(self):
return f"unduh {self.judul}.{self.format_file}"
class Audiobook(Buku):
def __init__(self, judul, penulis, tahun, stok=1, durasi_menit=60):
super().__init__(judul, penulis, tahun, stok)
self.durasi_menit = durasi_menit
def info(self):
return f"{super().info()} · audio {self.durasi_menit} menit"
class KatalogEntry:
def __init__(self, judul, sumber):
self.judul = judul
self.sumber = sumber
def info(self):
return f"Entri katalog: {self.judul} ({self.sumber})"
koleksi = [
Buku("ESP32 Praktis", "Budi", 2023, stok=2),
Ebook("Belajar Python", "Sari", 2024, format_file="pdf", ukuran_mb=4.5),
Audiobook("Cerita Sensor", "Ani", 2025, durasi_menit=90),
KatalogEntry("Datasheet DHT22", "vendor"),
]
for item in koleksi:
print(item.info())
if isinstance(item, Ebook):
print(" →", item.unduh())
print("isinstance ebook→Buku:", isinstance(koleksi[1], Buku))
print("type(katalog) is Buku:", type(koleksi[3]) is Buku)
Output yang diharapkan (kurang lebih):
ESP32 Praktis · Budi (2023) · stok 2
Belajar Python · Sari (2024) · stok 1 · PDF (4.5 MB)
→ unduh Belajar Python.pdf
Cerita Sensor · Ani (2025) · stok 1 · audio 90 menit
Entri katalog: Datasheet DHT22 (vendor)
isinstance ebook→Buku: True
type(katalog) is Buku: False
Kesalahan umum
| Gejala | Penyebab tipikal | Perbaikan |
|---|---|---|
Loop penuh isinstance panjang |
Menyalin perilaku ke pemanggil, bukan ke class | Pindahkan ke method bersama (info()) / override |
AttributeError: ... has no attribute 'info' |
Object di list tidak punya method yang diharapkan | Samakan antarmuka, atau jangan masukkan tipe itu ke koleksi |
Tipe baru memaksa ubah semua if |
Polymorphism diganti cabang tipe | Tambah class + method; biarkan loop lama |
| Bingung duck typing vs inheritance | Mengira harus selalu Anak(Induk) |
Warisi bila berbagi state/perilaku; duck typing OK untuk kontrak kecil |
isinstance “salah cabang” |
Cek anak setelah induk dengan urutan terbalik | Cek tipe lebih spesifik dulu, atau hindari hutan isinstance |
Latihan singkat
- Tambah
class Majalah(Buku)denganedisi, overrideinfo(), masukkan kekoleksi— pastikan loop lama tidak diubah. - Sengaja masukkan object tanpa
info()ke list — amatiAttributeError, lalu perbaiki. - Refactor satu fungsi yang penuh
isinstancemenjadi pemanggilan method bersama.
FAQ singkat
Apakah polymorphism wajib pakai inheritance?
Tidak. Inheritance memudahkan berbagi kode; duck typing cukup jika method-nya sama. Keduanya sah di Python.
Kapan isinstance masih boleh?
Saat ada aksi yang memang khas satu tipe dan belum layak digabung ke antarmuka bersama.
Apakah type(x) is Buku sama dengan isinstance?
Tidak. type(x) is Buku menolak anak class. Untuk “adalah Buku atau turunannya”, pakai isinstance — detailnya sudah muncul di Inheritance (#44).
Kenapa isinstance(ebook, Buku) True?
Karena pewarisan: ebook adalah Buku. Itu kekuatan polymorphism — dan sekaligus alasan hutan isinstance mudah salah urutan.
Bagaimana memaksa semua class punya method tertentu?
Itu ranah Abstraction & ABC (#46).
Kesimpulan & langkah berikutnya
Polymorphism membuat pemanggil tetap sederhana: panggil antarmuka bersama, biarkan tiap class menjawab dengan caranya. Hindari hutan isinstance; cadangkan untuk pengecualian yang benar-benar khas.
Artikel ini adalah #45 (ini) — langkah keenam Seri 3 setelah Inheritance (#44).
Lanjut ke Abstraction & ABC (#46): kontrak class abstract supaya subclass wajib mengimplementasikan method tertentu.
Seri 3 progress: 8/10 artikel live. Kamu di langkah #45 (ini). Prasyarat: Inheritance (#44) · Encapsulation (#43) · Attribute (#42) · Class & Object (#41) · Mengenal OOP (#40) · lanjut: Abstraction (#46).