Class adalah cetakan untuk membuat object, dan object adalah satu barang jadi yang dibuat dari cetakan itu. Bayangin blanko kartu menu di Warung Kopi Pak Darto. Tiap kartu punya kolom yang sama: "Nama: ___" dan "Harga: ___". Blankonya dirancang sekali, lalu tiap kartu diisi sendiri-sendiri: satu jadi kartu kopi susu Rp15.000, satu lagi teh manis Rp5.000. Blanko itu class, tiap kartu yang sudah terisi itu object.
🧪 Tebakan cepat: di class
Menu, method__init__punya tiga parameter:self,nama, danharga. Kamu memanggilMenu("kopi susu")dengan satu argumen saja. Python bilang kurang berapa argumen: dua, atau satu? Tebak dulu, jawabannya ada di bagian "__init__danself".
Membuat class dan object
class Menu:
def __init__(self, nama, harga):
self.nama = nama
self.harga = harga
def total(self, jumlah):
return self.harga * jumlah
kopi = Menu("kopi susu", 15000)
teh = Menu("teh manis", 5000)
print(kopi.nama) # kopi susu
print(kopi.total(3)) # 45000
print(teh.total(4)) # 20000
class Menu:membuat class baru bernamaMenu. Nama class ditulis PascalCase, huruf besar di awal tiap kata (Menu,MenuMinuman), beda dengan nama fungsi yang snake_case.- Fungsi yang ditulis di dalam class disebut method.
__init__dantotaldua-duanya method. Menu("kopi susu", 15000)membuat object baru dari class itu. Object juga disebut instance:kopiadalah instance dariMenu.kopi.namamembaca atribut, yaitu variabel milik object itu. Titiknya dibaca "punya":namapunyakopi.kopi.total(3)memanggil method milikkopi. Hasilnya15000 * 3, karenaself.hargadi dalamnya adalah harga milikkopi.kopidantehdibuat dari class yang sama, tapi atributnya terpisah.teh.total(4)memakai harga teh, 5000.
__init__ dan self
__init__ adalah method khusus yang dijalankan otomatis tiap kali object baru dibuat. Tugasnya mengisi atribut awal object itu. Method seperti ini disebut constructor. Begini yang terjadi saat Python menjalankan kopi = Menu("kopi susu", 15000):
| Langkah | Yang terjadi |
|---|---|
| 1 | Python membuat object Menu baru yang masih kosong |
| 2 | Python memanggil __init__ dengan self = object baru itu, nama = "kopi susu", harga = 15000 |
| 3 | self.nama = nama dan self.harga = harga menempelkan dua atribut ke object itu |
| 4 | Object yang sudah terisi diberikan ke variabel kopi |
selfadalah object yang sedang dikerjakan. Miripthisdi JavaScript, bedanya di Pythonselfditulis terang-terangan sebagai parameter pertama tiap method.- Kamu gak pernah mengirim
selfsendiri, Python yang mengisinya.kopi.total(3)sebenarnya dijalankan sebagaiMenu.total(kopi, 3):self=kopi,jumlah= 3. - Di
self.nama = nama, yang kiri atribut milik object, yang kanan parameter yang dikirim. Namanya boleh sama, tempatnya beda.
Karena self diisi Python, Menu("kopi susu") cuma kurang satu argumen, yaitu harga. Itu jawaban tebakannya:
Traceback (most recent call last):
File "/home/darto/warung.py", line 9, in <module>
kopi = Menu("kopi susu")
TypeError: Menu.__init__() missing 1 required positional argument: 'harga'
Method yang mengubah atribut
Method boleh mengubah atribut object-nya sendiri. Class Pesanan mencatat total belanja satu meja (kode ini lanjutan warung.py di atas, di bawah class Menu):
roti = Menu("roti bakar", 12000)
class Pesanan:
def __init__(self, meja):
self.meja = meja
self.total = 0
def tambah(self, menu, jumlah):
self.total = self.total + menu.harga * jumlah
print(self.total)
def batal(self, menu, jumlah):
potongan = menu.harga * jumlah
if potongan > self.total:
print("Gak bisa dibatalkan")
else:
self.total = self.total - potongan
print(self.total)
pesanan = Pesanan(5)
pesanan.tambah(kopi, 3) # 45000
pesanan.tambah(teh, 4) # 65000
pesanan.tambah(roti, 2) # 89000
pesanan.batal(teh, 30) # Gak bisa dibatalkan
self.total = 0di__init__: tiap pesanan baru mulai dari 0.self.total = self.total + ...membaca total lama milik object ini, menambahnya, lalu menyimpannya lagi ke object yang sama. Bentuk singkatnyaself.total += menu.harga * jumlah.- Hasilnya menempel di object. Setelah tiga kali
tambah,pesanan.totalbernilai 89000, total penjualan Pak Darto hari ini. batalmengecek dulu denganif. Potongan 150.000 lebih besar dari 89.000, jadi yang jalan cumaprint, danself.totalgak disentuh sama sekali.- Object boleh dikirim sebagai argumen:
menu.hargamembaca atribut milik objectMenuyang dikirim.
Atribut object dan atribut class
Variabel yang ditulis langsung di badan class, bukan lewat self., adalah atribut class: cuma ada satu, dipakai bersama semua object.
class Pesanan:
item = []
def __init__(self, meja):
self.meja = meja
def tambah(self, nama):
self.item.append(nama)
a = Pesanan(1)
b = Pesanan(2)
a.tambah("kopi susu")
b.tambah("teh manis")
print(a.item) # ['kopi susu', 'teh manis']
print(b.item) # ['kopi susu', 'teh manis']
self.itemdicari di object dulu. Objectagak punyaitem, jadi Python memakai milik class. Meja 1 dan meja 2 menulis ke list yang sama.- Perbaikannya: buat list-nya di
__init__denganself.item = []. Tiap object dapat list sendiri, dan hasilnya['kopi susu']dan['teh manis']. - Atribut class cocok untuk nilai yang memang sama untuk semua object, misalnya
NAMA_WARUNG = "Warung Kopi Pak Darto".
__str__, __repr__, dan __len__
Method yang namanya diapit dua garis bawah, seperti __init__, disebut dunder method (double underscore). Python memanggilnya sendiri di situasi tertentu. Tanpa __str__, print(kopi) cuma menampilkan nama class dan alamat memorinya, <__main__.Menu object at 0x1027ddd30> (angka alamatnya beda tiap kali jalan).
class Menu:
def __init__(self, nama, harga):
self.nama = nama
self.harga = harga
def __str__(self):
return f"{self.nama} ({self.harga})"
def __repr__(self):
return f"Menu('{self.nama}', {self.harga})"
kopi = Menu("kopi susu", 15000)
teh = Menu("teh manis", 5000)
print(kopi) # kopi susu (15000)
print(repr(kopi)) # Menu('kopi susu', 15000)
print([kopi, teh]) # [Menu('kopi susu', 15000), Menu('teh manis', 5000)]
__str__untuk pengguna: dipanggilprint(obj),str(obj), dan f-string. Isinya teks yang enak dibaca.__repr__untuk developer: dipanggilrepr(obj), ditampilkan REPL dan debugger, dan dipakai saat object ada di dalam list. Idealnya ditulis seperti kode yang bisa membuat object itu lagi.- Kalau cuma mau menulis satu, tulis
__repr__. Python memakainya juga untukprintsaat__str__gak ada. Sebaliknya gak berlaku: tanpa__repr__, list tetap mencetak<__main__.Menu object at ...>. - Keduanya harus
returnteks, bukanprint. __len__membuatlen(obj)jalan. KalauPesananpunyadef __len__(self): return len(self.item), makalen(pesanan)memanggilpesanan.__len__()dan memberi jumlah item. Tanpa method itu:TypeError: object of type 'Pesanan' has no len(). Nama lain seperti__size__atau__length__gak dikenal Python.
⚠️ Jebakan yang sering ketemu
- Lupa
selfdi parameter method.def total(jumlah):lalukopi.total(3)gagal:TypeError: Menu.total() takes 1 positional argument but 2 were given. "2 were given" karena Python ikut mengirimkopisebagaiself. - Lupa
self.saat menyimpan.nama = namadi__init__cuma mengisi variabel lokal yang hilang begitu__init__selesai.kopi.namajadiAttributeError: 'Menu' object has no attribute 'nama'. - Salah ketik
__init__.__int__dianggap method biasa, jadiMenu("kopi susu", 15000)ditolak:TypeError: Menu() takes no arguments. - List di badan class.
item = []di luar__init__dipakai bersama semua object. Buat di__init__denganself.item = [].
TL;DR: class Menu: adalah cetakan, Menu("kopi susu", 15000) membuat object (instance) darinya. __init__ adalah constructor yang jalan otomatis saat object dibuat dan mengisi atributnya lewat self.nama = nama. self adalah object yang sedang dikerjakan, diisi Python sendiri, jadi Menu("kopi susu") cuma kurang satu argumen: missing 1 required positional argument: 'harga'. Method adalah fungsi di dalam class, selalu dengan self sebagai parameter pertama, dan boleh mengubah atribut (self.total = self.total + ...). Atribut class dipakai bersama semua object, jadi list per object dibuat di __init__. Dunder method dipanggil Python sendiri: __str__ untuk print (pengguna), __repr__ untuk developer dan isi list, __len__ untuk len().