Statement match/case yang diperkenalkan Python 3.10 sering disebut “switch-case milik Python”, padahal kemampuannya jauh lebih besar: match tidak membandingkan nilai, melainkan mencocokkan struktur data dan mengikat bagian-bagianya ke variabel. Materi dasar pola literal dan pencocokan sederhana telah dibahas pada Chapter match-case. Pada Chapter ini kita naik level ke pola yang menjadikan structural pattern matching layak dipakai di kode produksi: sequence pattern, mapping pattern, class pattern, serta kombinasi OR, AS, dan guard.
Sequence dan Mapping Pattern untuk Payload #
Data nyata biasanya berbentuk struktur bersarang: list berisi dictionary, dictionary berisi list. Pattern sequence ([a, b]) dan pattern mapping ({"kunci": nilai}) mencocokkan bentuk tersebut dan langsung membongkar isinya. Contoh berikut menangani payload event mirip JSON:
def tangani(event):
match event:
case {"type": "klik", "pos": [x, y]}:
return f"klik pada ({x}, {y})"
case {"type": "ketik", "teks": str() as isi, "shift": True}:
return f"ketik huruf besar: {isi.upper()}"
case {"type": "ketik", "teks": str() as isi}:
return f"ketik: {isi}"
case {"type": "scroll", "arah": arah, "jumlah": n} if n > 0:
return f"scroll {arah} sebanyak {n}"
case _:
return "event tidak dikenal"
events = [
{"type": "klik", "pos": [120, 40]},
{"type": "ketik", "teks": "a", "shift": True},
{"type": "ketik", "teks": "z"},
{"type": "scroll", "arah": "bawah", "jumlah": 3},
{"type": "gestur"},
]
for e in events:
print(tangani(e))Output yang Dihasilkan:
klik pada (120, 40)
ketik huruf besar: A
ketik: z
scroll bawah sebanyak 3
event tidak dikenalMari kita bedah pola-pola pada function tangani:
- Baris 3 (
case {"type": "klik", "pos": [x, y]}): pattern mapping mencocokkan dictionary yang memiliki kunci"type"bernilai"klik"dan kunci"pos"berupa sequence dua elemen; elemen tersebut diikat kexdanybaru setelah seluruh struktur cocok. - Baris 5 (
case {"type": "ketik", "teks": str() as isi, "shift": True}): sub-polastr()memastikan nilai bertipe string,as isimengikatnya, dan"shift": Truehanya cocok bila nilainya benar-benarTrue— urutan case menentukan bahwa varianshiftdicek lebih dulu. - Baris 9 (
case ... if n > 0:): guardifmenjalankan kondisi Python biasa setelah struktur cocok; event scroll denganjumlahnol atau negatif jatuh ke case berikutnya.
Dua aturan penting di balik layar: pattern sequence hanya cocok untuk sequence (list, tuple), bukan set atau string; dan pattern mapping hanya cocok untuk mapping — kunci ekstra pada data tetap diperbolehkan, karena pencocokan bersifat sebagian, bukan menyeluruh.
Class Pattern dengan match_args #
Class pattern memungkinkan pencocokan berdasarkan tipe dan atribut. Atribut posisi pada pola Titik(0, y) dibaca dari atribut class __match_args__ — tuple yang menyatakan urutan atribut yang boleh dibongkar:
class Titik:
__match_args__ = ("x", "y")
def __init__(self, x, y):
self.x = x
self.y = y
def deskripsi(titik):
match titik:
case Titik(0, 0):
return "titik asal"
case Titik(0, y):
return f"pada sumbu Y, y={y}"
case Titik(x, 0):
return f"pada sumbu X, x={x}"
case Titik(x, y):
return f"titik bebas: ({x}, {y})"
print(deskripsi(Titik(0, 0)))
print(deskripsi(Titik(0, 7)))
print(deskripsi(Titik(3, 0)))
print(deskripsi(Titik(2, 5)))Output yang Dihasilkan:
titik asal
pada sumbu Y, y=7
pada sumbu X, x=3
titik bebas: (2, 5)Pada baris case Titik(0, y), interpreter Python memanggil isinstance(titik, Titik) terlebih dahulu, lalu membaca titik.x dan titik.y sesuai urutan __match_args__ untuk dicocokkan dengan 0 dan diikat ke y. Tanpa __match_args__, kita masih bisa memakai pola atribut bernama seperti case Titik(x=0, y=y) — hasilnya sama, hanya lebih panjang ditulis.
OR Pattern, AS Pattern, dan Guard #
Tiga penyusun kecil yang sering dipakai bersama: OR pattern | mengizinkan beberapa alternatif dalam satu case, AS pattern as mengikat nilai yang dicocokkan (bukan bagian isinya), dan guard menjalankan kondisi tambahan:
def tanggapi_status(status):
match status:
case 200 | 201 | 204:
return "sukses"
case 404 | 410 as kode:
return f"sumber daya tidak ditemukan ({kode})"
case int() as kode if kode >= 500:
return f"galat server ({kode})"
case _:
return "status tidak dikenal"
for s in (200, 404, 503, 302):
print(s, "->", tanggapi_status(s))Output yang Dihasilkan:
200 -> sukses
404 -> sumber daya tidak ditemukan (404)
503 -> galat server (503)
302 -> status tidak dikenalPada baris case 404 | 410 as kode, operator as mengikat keseluruhan nilai subject (404) ke kode — berbeda dari pola sequence yang mengikat bagian-bagian internal. Pola int() adalah class pattern tanpa argumen yang hanya menguji tipe, sehingga case int() as kode if kode >= 500 membaca “jika status bertipe int apa pun dan nilainya >= 500”.
Capture Bukan Literal: Jebakan Nama Polos #
Perbedaan paling berbahaya bagi pemula: nama polos di dalam case adalah pola capture, bukan pembanding nilai. Nama yang memuat titik (misalnya Kode.OK) dibaca sebagai nilai, sedangkan nama tanpa titik mengikat apa pun:
class Kode:
OK = 200
HILANG = 404
def dengan_nama_dotted(kode):
match kode:
case Kode.OK: # dotted name dibaca sebagai nilai 200
return "nilai konstanta: sukses"
case Kode.HILANG:
return "nilai konstanta: hilang"
case nilai: # nama polos sebagai case terakhir: capture
return f"tertangkap: {nilai}"
print(dengan_nama_dotted(200))
print(dengan_nama_dotted(404))
print(dengan_nama_dotted(500))Output yang Dihasilkan:
nilai konstanta: sukses
nilai konstanta: hilang
tertangkap: 500Interpreter Python bahkan aktif melindungi kita dari versi keliru. Kode berikut menolak dikompilasi karena capture di posisi awal membuat case berikutnya mustahil tercapai:
def dengan_nama_polos(kode):
match kode:
case kode_ok: # nama polos SELALU menangkap nilai
return "selalu cocok"
case 500:
return "tidak pernah tercapai"Output yang Dihasilkan (dicetak interpreter Python ke stderr):
File "demo.py", line 3
case kode_ok: # nama polos SELALU menangkap nilai
^^^^^^^
SyntaxError: name capture 'kode_ok' makes remaining patterns unreachableKapan match Kalah dari if/elif #
Pencocokan pola berjalan berurutan dari atas ke bawah seperti if/elif, dan setiap pengujian pola memanggil isinstance serta pengambilan atribut — bukan magic hash lookup. Untuk membandingkan satu nilai terhadap beberapa literal sederhana, if/elif biasa sama jelasnya dan tidak menambah mesin baru. match baru unggul ketika ada struktur untuk dibongkar: payload bersarang, tipe berbeda-beda, atau kombinasi nilai dan bentuk. Jika sebuah case hanya berisi case x: lalu if x == ... di dalam badannya, itu sinyal kuat pola sedang dipaksa dan if/elif akan lebih jernih.