Belajar dengan membaca secara berurutan

Special Method — Mengajari Class Cara + dan print Berperilaku

Pelajari special method (dunder method) Python. Sesuaikan + dengan __add__, kontrol output print dengan __str__, dan definisikan ulang == dengan __eq__ — semuanya dengan diagram.

Sebelumnya kita menyusun instance, class, dan static method. Sekarang kita bahas jenis lain — special method (alias dunder method).

Apa itu special method? — "Dunder Method"

Method seperti __init__ dan __str__ — nama yang diapit dua underscore di tiap sisi — disebut special method. Karena duduk di antara double underscores, mereka juga disebut dunder method.

Hal kunci tentang special method adalah kamu tidak memanggilnya langsung. Python memanggil mereka otomatis ketika kamu melakukan operasi tertentu. Tulis v1 + v2 dan Python memanggil v1.__add__(v2) di balik layar. Tulis print(p) dan p.__str__() dipanggil. Tulis a == b dan a.__eq__(b) berjalan.

Operator dan special method-nya
Yang kamutulisPythonmengubahMethoddipanggilv1 + v2__add__print(p)__str__a == b__eq__
Operator dan fungsi bawaan Python memanggil dunder method yang cocok di balik layar. Definisikan mereka di class dan tipe milikmu bisa pakai +, ==, dan teman-teman.

__add__ — Mendefinisikan operator +

Ambil + sebagai contoh paling jelas. Misalkan kamu punya class Money untuk jumlah dalam yen, dan kamu ingin Money(300) + Money(500) menghasilkan Money(800). Coba menjumlahkannya begitu saja dan Python akan melempar TypeError karena tidak tahu cara menambahkan Money dengan Money.

Cara mengajari Python cara menambahkannya adalah method __add__. Definisikan def __add__(self, other): dan kembalikan instance baru yang dibangun dari self (sisi kiri) dan other (sisi kanan). Sekarang + bekerja pada class-mu.

class Money:
    def __init__(self, amount):
        self.amount = amount

    def __add__(self, other):                 # dipanggil saat menulis +
        return Money(self.amount + other.amount)

wallet  = Money(300)
payment = Money(500)
total   = wallet + payment                    # sebenarnya wallet.__add__(payment)
print(total.amount)                           # 800
Apa yang v1 + v2 lakukan di balik layar
wallet+ paymentwallet.__add__(payment)self =walletother =paymentreturn Money(self.amount + other.amount)mengembalikanMoney(800)diubah
Tulis + dan Python memanggil self.__add__(other). self adalah operand kiri, other adalah yang kanan. Apapun instance baru yang kamu kembalikan menjadi hasil dari +.

Implementasikan __add__ di Money agar + menjumlahkan dua saldo.

① Definisikan class Money: dengan __init__(self, amount) yang menetapkan self.amount = amount.

② Definisikan __add__(self, other) yang mengembalikan Money(self.amount + other.amount).

③ Bangun wallet = Money(300) dan payment = Money(500), lalu print total.amount di mana total = wallet + payment.

(Begitu berjalan benar, penjelasan akan muncul.)

Python Editor

Jalankan kode untuk melihat output

__str__ dan __repr__ — Dua jenis representasi string

Berikutnya: special method yang dipanggil ketika instance dikonversi ke string. Ada dua, dengan tujuan berbeda.

- __str__ — dipanggil oleh print(p) dan str(p). String yang ramah pengguna dan mudah dibaca.

- __repr__ — dipanggil di REPL atau saat debugging. String yang mirip kode, dengan detail.

Tanpa override, print(user) menampilkan sesuatu seperti <__main__.User object at 0x...> — cukup tidak berguna. Definisikan __str__ untuk tampilan rapi, dan definisikan juga __repr__ agar debugging menunjukkan tipe dan kontennya sekilas.

class User:
    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def __str__(self):                       # untuk print() / str()
        return f"{self.name} (umur {self.age})"

    def __repr__(self):                      # untuk debugging
        return f"User(name={self.name!r}, age={self.age})"

u = User("Budi", 30)
print(u)             # Budi (umur 30)              <- __str__
print(repr(u))       # User(name='Budi', age=30)   <- __repr__
Kapan pakai __str__ vs __repr__
__str__ (untuk pengguna)
  • Dipanggil oleh print(u) dan str(u)
  • Tujuan: string untuk dibaca pengguna akhir
  • Contoh: Budi (umur 30)
__repr__ (untuk developer)
  • Dipanggil oleh repr(u) dan REPL interaktif
  • Jadi cadangan saat __str__ tidak ada selama print
  • Tujuan: string debug menunjukkan tipe dan konten
  • Contoh: User(name='Budi', age=30)
Ideal mendefinisikan keduanya, tetapi kalau hanya satu, jadikan itu __repr__ — membuat debugging jauh lebih mudah.

Implementasikan __str__ dan __repr__ di User dan bandingkan apa yang ditunjukkan print dan repr.

① Definisikan class User: dengan __init__(self, name, age) yang menetapkan self.name / self.age.

② Definisikan __str__(self) yang mengembalikan f"{self.name} (umur {self.age})".

③ Definisikan __repr__(self) yang mengembalikan f"User(name={self.name!r}, age={self.age})". Tanda !r setelah self.name berarti sisipkan hasil pemanggilan repr() pada nilai — string keluar dengan single quote ('Budi') bukan teks polos (Budi).

④ Bangun u = User("Budi", 30), lalu jalankan baik print(u) maupun print(repr(u)) untuk melihat perbedaannya.

Python Editor

Jalankan kode untuk melihat output

__eq__ — Mendefinisikan ==

Sekarang tentang kesetaraan. Saat kamu menulis a == b, Python memanggil a.__eq__(b) secara internal. Jika class-mu tidak mendefinisikan __eq__, default-nya adalah «apakah mereka object yang sama di memory?» (cek id).

Misalkan kamu punya class Coupon dan kamu ingin dua kupon dengan kode sama dianggap kupon yang sama — meski nilai diskon berbeda. Itu kesetaraan «tingkat bisnis», dan __eq__ adalah tempat kamu menjelaskannya.

Bagaimana __eq__ mengubah perilaku ==
c1 == c2tanpa__eq__cek id(alamat memory)dengan__eq__self.code== other.codedefaultdidefinisikan
Tanpa __eq__, == adalah cek id — konten sama tapi instance terpisah tetap False. Dengan __eq__, kamu bisa membandingkan berdasar konten (code).
class Coupon:
    def __init__(self, code, discount):
        self.code     = code
        self.discount = discount

    def __eq__(self, other):
        return self.code == other.code        # kode sama = kupon sama

c1 = Coupon("SPRING10", 0.10)
c2 = Coupon("SPRING10", 0.20)               # diskon beda, kode sama
c3 = Coupon("SUMMER15", 0.15)

print(c1 == c2)   # True  (kode cocok)
print(c1 == c3)   # False (kode beda)

Apa yang terjadi tanpa __eq__?

Jika kamu tidak mendefinisikan __eq__, c1 == c2 mengecek apakah mereka object yang sama di memory (literal menunjuk box yang sama). Bahkan jika setiap atribut cocok sempurna, dua instance yang dibangun terpisah hidup di alamat memory yang berbeda dan hasilnya False. Kapanpun kamu mau «sama menurut konten», definisikan __eq__ sendiri.

Implementasikan __eq__ di Coupon agar dua kupon sama saat code mereka cocok.

① Definisikan class Coupon: dengan __init__(self, code, discount) yang menetapkan self.code dan self.discount.

② Definisikan __eq__(self, other) yang mengembalikan self.code == other.code.

③ Bangun tiga kupon — Coupon("SPRING10", 0.10), Coupon("SPRING10", 0.20), dan Coupon("SUMMER15", 0.15) — dan print dua perbandingan ==.

Python Editor

Jalankan kode untuk melihat output

Special method umum lainnya — __call__ / __len__ / __bool__

Selain empat yang telah kita bahas, beberapa special method lain sering muncul. Tiga yang patut diketahui sekarang:

- __call__ — membuat instance bisa dipanggil seperti fungsi (sintaks obj(...))

- __len__ — menentukan apa yang dikembalikan len(obj)

- __bool__ — menentukan bagaimana instance dievaluasi sebagai nilai kebenaran dalam if obj: atau bool(obj)

Masing-masing mengajari operasi bawaan — pemanggilan fungsi, len(), cek truthiness if — ke class buatanmu. Logger yang mengakumulasi entri log adalah contoh bagus untuk meletakkan ketiganya pada satu class.

class Logger:
    def __init__(self, name):
        self.name = name
        self.log  = []

    def __call__(self, message):                    # logger("...") jalan
        self.log.append(message)
        return f"[{self.name}] {message}"

    def __len__(self):                               # untuk len(logger)
        return len(self.log)

    def __bool__(self):                              # untuk if logger:
        return len(self.log) > 0

app = Logger("app")
print(app("Aplikasi mulai"))     # [app] Aplikasi mulai
print(app("Login berhasil"))     # [app] Login berhasil
print(len(app))                   # 2
if app:
    print("Ada log")              # Ada log
Mengajari Logger berbicara sintaks bawaan
app('msg')app.__call__('msg')len(app)app.__len__()if app:app.__bool__()jadijadijadi
Sintaks familiar — logger(...), len(logger), if logger: — diajarkan ke class kustommu lewat tiga dunder yang cocok.

Bagaimana kalau tidak mendefinisikan __bool__?

Saat __bool__ tidak ada, Python jatuh ke __len__. Panjang 0 jadi False; selain itu jadi True. Kalau keduanya tidak ada, instance selalu truthy, apapun keadaannya. Itulah aturan yang sama yang membuat list kosong dan string kosong dievaluasi False.

Implementasikan ketiga special method di Logger agar menambahkan pesan, menghitung, dan mengecek kekosongan semuanya berjalan dengan sintaks bawaan.

① Definisikan class Logger: dengan __init__(self, name) yang menetapkan self.name = name dan self.log = [].

② Definisikan __call__(self, message): tambahkan message ke self.log, lalu kembalikan f"[{self.name}] {message}".

③ Definisikan __len__(self) yang mengembalikan len(self.log).

④ Definisikan __bool__(self) yang mengembalikan len(self.log) > 0.

⑤ Bangun error_log = Logger("error"), lalu jalankan berurutan: print(bool(error_log))error_log("Error DB")print(len(error_log))print(bool(error_log)).

Python Editor

Jalankan kode untuk melihat output

Masih banyak lagi — __hash__ (untuk dipakai sebagai key set/dict), __lt__ / __gt__ (perbandingan < / >), __getitem__ (sintaks obj[key]), __iter__ (iterasi for x in obj:), dan lainnya. Kamu tidak perlu menghafal semuanya. Cukup simpan peta mental ini: «kalau kamu mau mengajari operasi bawaan ke class-mu, kemungkinan ada dunder yang cocok». Lalu cari saat kamu butuh.

Special methodSintaksKapan dipanggil
__init__Money(300)Saat membuat instance
__add__a + bOperator +
__str__print(p) / str(p)String untuk pengguna
__repr__repr(p) / tampilan REPLString untuk developer
__eq__a == bPerbandingan kesetaraan
__call__obj(...)Panggilan gaya fungsi
__len__len(obj)Panjang
__bool__if obj: / bool(obj)Truthiness
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Saat result = a + b berjalan, method mana yang dipanggil Python di balik layar?

Soal 2Mana deskripsi __str__ dan __repr__ yang paling akurat?

Soal 3Jika class tidak mendefinisikan __eq__, apa yang dibandingkan a == b? (Keduanya instance dari class yang sama.)