OOP Dasar di Python
class, __init__, method: cukup paham konsepnya karena objek pandas bekerja dengan cara ini.
OOP: cetakan kue dan kuenya
Analogi singkat: class adalah cetakan kue, objek adalah kue yang dicetak. Dari satu cetakan (class Produk) kamu bisa membuat banyak kue (objek kopi, teh) yang bentuknya sama tapi isinya beda-beda. Kenapa analyst perlu tahu ini? Karena kamu memakai objek setiap hari tanpa sadar: DataFrame itu objek, Series itu objek. Memahami class bikin dokumentasi pandas jauh lebih masuk akal: kamu langsung paham kenapa menulis df.head() bukan head(df).
Contoh 1: class pertamamu
class Produk:
def __init__(self, nama, harga):
self.nama = nama
self.harga = harga
def info(self):
return f"{self.nama}: Rp{self.harga:,}"
kopi = Produk("Kopi Tubruk", 15000)
teh = Produk("Teh Manis", 8000)
print(kopi.info()) # Kopi Tubruk: Rp15,000
print(teh.info()) # Teh Manis: Rp8,000Tiga istilah kunci. __init__ adalah constructor yang jalan otomatis saat objek dibuat (di sinilah data "dituang ke cetakan"). self merujuk ke objek itu sendiri, tempat menyimpan data miliknya. Method adalah fungsi yang menempel di class dan selalu menerima self sebagai parameter pertama: saat kamu memanggil kopi.info(), Python otomatis mengisi self dengan kopi.
Catatan teknis: Inilah kenapa kamu menulis
df.head()bukanhead(df).dfadalah objek DataFrame,head()adalah method miliknya. Setelah paham pola ini, seluruh API pandas terasa konsisten: objek menyimpan data, method melakukan sesuatu dengan data itu.
Contoh 2 (realistis): class Transaksi untuk rekap penjualan
Class bersinar saat data punya perilaku: bukan cuma menyimpan, tapi juga bisa menghitung dirinya sendiri.
class Transaksi:
def __init__(self, produk, jumlah, harga_satuan):
self.produk = produk
self.jumlah = jumlah
self.harga_satuan = harga_satuan
def total(self):
return self.jumlah * self.harga_satuan
def info(self):
return f"{self.produk} x{self.jumlah} = Rp{self.total():,}"
data = [("Kopi", 3, 15000), ("Teh", 2, 8000), ("Kopi", 1, 15000)]
transaksi = [Transaksi(p, j, h) for p, j, h in data]
omzet = sum(t.total() for t in transaksi)
for t in transaksi:
print(t.info())
print("Total omzet: Rp", f"{omzet:,}")Perhatikan: logika "total = jumlah x harga" tertulis sekali di method total(), lalu dipakai di mana-mana. Kalau aturan berubah (misal tambah pajak), kamu mengedit satu method saja.
Sekilas inheritance: cetakan turunan
Class bisa mewarisi class lain, lalu menambah atau mengubah perilakunya:
class ProdukDiskon(Produk):
def __init__(self, nama, harga, diskon_persen):
super().__init__(nama, harga)
self.diskon_persen = diskon_persen
def info(self):
akhir = self.harga * (1 - self.diskon_persen / 100)
return f"{self.nama}: Rp{akhir:,.0f} (diskon {self.diskon_persen}%)"
promo = ProdukDiskon("Kopi Tubruk", 15000, 20)
print(promo.info()) # Kopi Tubruk: Rp12,000 (diskon 20%)super().__init__(...) memanggil constructor class induk, lalu class anak menambah diskon_persen dan menimpa info(). Cukup sampai sini untuk kebutuhan analyst: fokusmu tetap memakai objek (pandas), bukan merancang hierarki class.
Kesalahan umum pemula
SALAH: Lupa self di definisi method.
class Produk:
def info(): # TypeError saat dipanggil!
return "info"BENAR: Method selalu menerima self sebagai parameter pertama:
class Produk:
def info(self):
return f"{self.nama}: Rp{self.harga:,}"SALAH: Mengakses atribut yang tidak pernah di-set di __init__.
class Produk:
def __init__(self, nama):
self.nama = nama
kopi = Produk("Kopi")
print(kopi.harga) # AttributeError: 'Produk' object has no attribute 'harga'BENAR: Set semua atribut yang dibutuhkan di __init__:
class Produk:
def __init__(self, nama, harga):
self.nama = nama
self.harga = hargaSALAH: Mengira mengubah satu objek mengubah semua objek (atau sebaliknya).
kopi = Produk("Kopi", 15000)
teh = Produk("Teh", 8000)
kopi.harga = 16000 # hanya kopi yang berubah
print(teh.harga) # 8000, teh tidak ikut berubahBENAR: Setiap objek punya datanya sendiri (yang disimpan lewat self). Mengubah kopi.harga tidak menyentuh teh.harga. Inilah gunanya cetakan: banyak kue, masing-masing punya isi sendiri.
SALAH: Memanggil method tanpa tanda kurung, lalu heran kenapa tidak jalan.
print(kopi.info) # <bound method ...>, bukan hasilnya!BENAR: Method dipanggil dengan kurung, seperti fungsi:
print(kopi.info()) # Kopi: Rp16,000Tantangan
Class Transaksi
Buat class Transaksi dengan __init__(produk, jumlah, harga_satuan) dan method total() yang mengembalikan jumlah*harga. Buat 2 objek, print total masing-masing dan total gabungan.