Belajar dengan membaca secara berurutan

enum dan dataclasses — Konstanta Bernama dan Data Class

Pelajari pengganti konstanta string Enum, penomoran otomatis dan urutan IntEnum+auto(), boilerplate @dataclass, plus field(default_factory=list) lewat contoh.

Dua modul untuk menjadikan makna nilai eksplisit. enum membiarkan kamu menggantikan literal string yang tersebar di kodemu dengan konstanta bernama, sehingga kesalahan ketik muncul saat runtime alih-alih lewat diam-diam. dataclasses menyediakan cara untuk mendefinisikan "class yang hanya menyimpan data" dalam satu baris, menghilangkan boilerplate __init__ / __eq__ / __repr__.

Enum — ganti literal string dengan konstanta bernama

Ketika literal string seperti "paid" / "shipped" tersebar di kodemu, kesalahan ketik seperti "shippped" lolos sampai runtime, autocomplete tidak membantu, dan refactoring rapuh. Enum menyelesaikan ini dengan mendefinisikan kumpulan konstanta sebagai class — nama yang kamu definisikan autocomplete di editormu, kesalahan ketik melempar AttributeError langsung, iterasi atas semua member bekerja secara default, dan kamu mendapatkan nilai aman untuk dipakai sebagai key dict atau label switch.

# String status tersebar di kode
if status == "paid":
    ship_order(order_id)
elif status == "shippped":   # Salah ketik — seharusnya "shipped", tetapi kamu tidak akan menyadarinya sampai runtime
    notify_shipped(order_id)
elif status == "cancelled":
    refund(order_id)
Literal string vs. Enum
if status == "paid":(literal string)Salah ketik "paied"tidak melempar exception→ Bug tetap tersembunyiif status == OrderStatus.PAID:(Enum)OrderStatus.PAEID→ AttributeError→ Tertangkap segera
String mentah tidak autocomplete dan kesalahan ketik lolos sampai runtime. Enum hanya mengizinkan nama yang kamu definisikan, jadi kamu mendapatkan autocomplete, deteksi kesalahan ketik, dan iterasi semua member sekaligus.
from enum import Enum

class OrderStatus(Enum):
    PENDING = "pending"
    PAID = "paid"
    SHIPPED = "shipped"
    CANCELLED = "cancelled"

# Akses member: setiap member membawa name dan value
print(OrderStatus.PAID)            # OrderStatus.PAID
print(OrderStatus.PAID.name)       # 'PAID'
print(OrderStatus.PAID.value)      # 'paid'

# Bandingkan dengan ==
status = OrderStatus.PAID
if status == OrderStatus.PAID:
    print("Pembayaran diterima")

Definisikan status order sebagai Enum dan baca info member.

① Impor Enum dari modul enum

② Definisikan class Enum OrderStatus dengan empat member PENDING / PAID / SHIPPED / CANCELLED (value adalah string huruf kecil "pending" / "paid" / "shipped" / "cancelled")

③ Cetak OrderStatus.PAID.name sebagai PAID name: ◯◯

④ Cetak OrderStatus.PAID.value sebagai PAID value: ◯◯

⑤ Cetak semua nama member sebagai All members: ◯ (kamu bisa beriterasi dengan for s in OrderStatus)

(Jika kode kamu jalan dengan benar, penjelasannya akan muncul.)

Python Editor

Jalankan kode untuk melihat output

Bangun fungsi yang membandingkan member Enum di if/elif dan mengembalikan pesan per status. Bercabang pada kesetaraan member-ke-member alih-alih literal string adalah cara yang lebih aman untuk menulisnya.

① Definisikan OrderStatus dari Latihan 1

② Definisikan fungsi get_message(status) yang memakai if/elif atas setiap member untuk mengembalikan: PENDING → "Menunggu pembayaran", PAID → "Menyiapkan pengiriman", SHIPPED → "Dikirim", CANCELLED → "Dibatalkan"

③ Cetak get_message(OrderStatus.PAID) sebagai PAID: ◯

④ Cetak get_message(OrderStatus.SHIPPED) sebagai SHIPPED: ◯

Python Editor

Jalankan kode untuk melihat output

IntEnum dan auto — penomoran otomatis dan perbandingan numerik

IntEnum adalah Enum yang mewarisi dari int, jadi member membandingkan dan beroperasi aritmatika sebagai integer. Ini pilihan tepat untuk konstanta di mana urutan numerik penting — prioritas, level, ranking. auto() adalah fungsi yang menugaskan value secara otomatis menggantikan menulisnya dengan tangan: jajarkan panggilan auto() dan mereka menjadi 1, 2, 3, 4... dalam urutan definisi.

Ketika angka spesifik tidak penting (hanya urutannya), auto() lebih aman karena menambah atau menghapus member tidak memerlukan menulis ulang angka dengan tangan.

IntEnum + auto
class Priority(IntEnum): LOW = auto() MEDIUM = auto()auto() menomori1, 2, 3Priority.LOW < Priority.HIGH→ True (perbandingan int)
auto() otomatis menomori 1, 2, 3, .... IntEnum dibandingkan dengan int, jadi Priority.LOW < Priority.HIGH berfungsi — urutan numerik mengkodekan prioritas.

Definisikan IntEnum Priority dengan auto() dan sortir beberapa tugas dari prioritas tinggi ke rendah. Konfirmasi di skenario dunia nyata bahwa auto() menomori otomatis dan IntEnum bisa membandingkan dan menyortir sebagai int.

① Impor IntEnum dan auto dari enum

② Definisikan class IntEnum Priority dengan empat member LOW / MEDIUM / HIGH / URGENT (semua value auto())

③ Bangun list semua value member dan cetak sebagai Penomoran: ◯ (mengonfirmasi auto() menugaskan 1, 2, 3, 4)

④ Sortir list tugas [("Pembersihan", Priority.LOW), ("Balas email", Priority.HIGH), ("Siapkan materi", Priority.URGENT), ("Tinjau", Priority.MEDIUM)] dari prioritas tinggi ke rendah, kemudian di bawah judul Urutan eksekusi: cetak setiap tugas dalam bentuk - name (priority)

Python Editor

Jalankan kode untuk melihat output

@dataclass — definisikan class penyimpan data dalam satu baris

Menulis "class biasa dengan hanya field" dengan tangan berarti mendefinisikan __init__ untuk menetapkan atribut, __eq__ (dunder method yang dipanggil untuk perbandingan ==) untuk kesetaraan konten, __repr__ (dunder method yang dipanggil oleh print dan REPL) untuk tampilan yang mudah dibaca, dan seterusnya — pola boilerplate yang sama berbaris setiap kali. Satu decorator @dataclass menghasilkan semua itu otomatis dari deklarasi field dengan type hint kamu.

Dengan kata lain, hanya menjajarkan atribut dengan type hint membangun seluruh class — kamu mendapatkan fitur yang sama dengan kode jauh lebih sedikit daripada class buatan tangan.

Apa yang @dataclass hasilkan otomatis
@dataclassclass Order: id: int customer: str→ Dibuat otomatis__init__Inisialisasi atribut__eq__== jika semua field cocok__repr__Order(id=..., customer=...)
Cukup deklarasikan field dengan type hint dan kamu mendapatkan __init__ / __eq__ / __repr__ gratis. field(default_factory=list) membiarkan kamu menetapkan default mutable seperti list kosong dengan aman, dan frozen=True mengubah class menjadi immutable (perubahan atribut diblokir).

Pakai default_factory untuk default mutable

Mencoba men-default list dengan @dataclass dengan menulis items: list = [] melempar SyntaxError (atau peringatan deprecation). Ini perlindungan terhadap bug klasik "setiap instance berbagi list yang sama". Pakai field(default_factory=list), yang membuat list kosong segar per instance, membuatnya aman. Ide yang sama untuk dict / set: field(default_factory=dict).

Definisikan Order dengan @dataclass dan konfirmasi __eq__ dan __repr__ yang dihasilkan otomatis.

① Impor dataclass dan field dari dataclasses

② Definisikan class Order yang didekorasi dengan @dataclass — empat field: id: int, customer: str, items: list = field(default_factory=list), is_paid: bool = False

③ Bangun instance dengan Order(id=1234, customer="Budi", items=["apple", "banana"]) dan cetak langsung (__repr__ yang dihasilkan otomatis aktif)

④ Bangun instance kedua dengan konten yang sama dan cetak hasil perbandingan dengan == sebagai Sama: True / False

⑤ Ubah is_paid instance pertama ke True, kemudian bandingkan dengan == lagi dan cetak sebagai Sama setelah perubahan: True / False

Python Editor

Jalankan kode untuk melihat output
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Apa keuntungan mengganti perbandingan literal string "paid" dengan Enum?

Soal 2Apa keuntungan auto() pada IntEnum?

Soal 3Mana cara yang benar untuk men-default field ke list di @dataclass?