13. Membuat Pilihan dengan match dan case (Structural Pattern Matching)
Saat program kamu perlu membuat keputusan berdasarkan beberapa kemungkinan nilai atau pola, kamu sudah belajar menggunakan rangkaian if-elif-else dari Bab 8. Python 3.10 memperkenalkan alternatif yang kuat bernama structural pattern matching menggunakan statement match dan case. Fitur ini memberikan cara yang lebih rapi dan ekspresif untuk menangani skenario pengambilan keputusan yang kompleks.
Pattern matching lebih dari sekadar perbandingan nilai sederhana. Ini memungkinkan kamu mencocokkan struktur dan bentuk data, mengekstrak nilai dari objek yang kompleks, dan mengekspresikan keputusan multi-arah dalam bentuk yang lebih mudah dibaca. Walaupun rangkaian if-elif-else bekerja sangat baik untuk banyak situasi, statement match-case unggul saat kamu berurusan dengan banyak kasus yang berbeda, terutama saat bekerja dengan data terstruktur.
13.1) Memperkenalkan Statement match dan case (Membangun dari if-elif Bab 8)
13.1.1) Struktur Dasar match-case
Statement match memeriksa sebuah nilai (disebut subject) dan membandingkannya dengan satu atau lebih pattern yang didefinisikan dalam klausa case. Saat sebuah pattern cocok, Python mengeksekusi blok kode yang terkait dengan case tersebut.
Berikut struktur dasarnya:
match subject:
case pattern1:
# Kode yang dieksekusi jika pattern1 cocok
case pattern2:
# Kode yang dieksekusi jika pattern2 cocok
case pattern3:
# Kode yang dieksekusi jika pattern3 cocokMari mulai dengan contoh sederhana yang menunjukkan konsep dasarnya:
# Handler sederhana untuk kode status HTTP
status_code = 404
match status_code:
case 200:
print("Success: Request completed")
case 404:
print("Error: Page not found")
case 500:
print("Error: Server error")Output:
Error: Page not foundDalam contoh ini, statement match memeriksa status_code (subject). Python mengecek setiap pattern case secara berurutan. Saat menemukan bahwa status_code sama dengan 404, Python mengeksekusi blok kode yang sesuai lalu keluar dari statement match. Case yang tersisa tidak diperiksa.
13.1.2) Perbedaan match-case dengan if-elif-else
Kamu mungkin bertanya: "Bukankah ini bisa saya tulis dengan if-elif-else?" Ya, bisa:
status_code = 404
if status_code == 200:
print("Success: Request completed")
elif status_code == 404:
print("Error: Page not found")
elif status_code == 500:
print("Error: Server error")Output:
Error: Page not foundKedua versi menghasilkan hasil yang sama. Namun, match-case menawarkan beberapa keuntungan:
- Maksud yang lebih jelas: Statement
matchsecara eksplisit menunjukkan bahwa kamu mengecek satu nilai terhadap banyak kemungkinan - Lebih sedikit pengulangan: Kamu tidak mengulang nama variabel pada setiap perbandingan
- Pattern yang lebih kuat: Seperti yang akan kita lihat,
match-casebisa melakukan jauh lebih banyak daripada sekadar pengecekan kesetaraan sederhana - Keterbacaan lebih baik: Untuk pohon keputusan yang kompleks,
match-casesering kali lebih mudah dipahami
13.1.3) Saat Tidak Ada Pattern yang Cocok
Apa yang terjadi jika tidak ada pattern yang cocok? Statement match akan selesai begitu saja tanpa mengeksekusi blok case mana pun:
# Pengecek peran pengguna
user_role = "guest"
match user_role:
case "admin":
print("Full system access granted")
case "moderator":
print("Content management access granted")
case "editor":
print("Editing access granted")
print("Role check complete")Output:
Role check completeKarena "guest" tidak cocok dengan pattern mana pun, tidak ada blok case yang dieksekusi. Program lanjut ke kode setelah statement match. Perilaku ini penting untuk dipahami—berbeda dengan rangkaian if-elif-else di mana kamu bisa menambahkan klausa else terakhir untuk menangkap semua kasus lainnya, statement match dasar tanpa pattern penangkap semua akan diam-diam tidak melakukan apa pun jika tidak ada pattern yang cocok.
13.1.4) Contoh Praktis: Sistem Pemilihan Menu
Mari buat contoh yang lebih lengkap yang menunjukkan kejelasan match-case untuk menangani pilihan pengguna:
# Sistem pemesanan restoran
menu_choice = 3
match menu_choice:
case 1:
item = "Caesar Salad"
price = 8.99
print(f"You ordered: {item} - ${price}")
case 2:
item = "Grilled Chicken"
price = 14.99
print(f"You ordered: {item} - ${price}")
case 3:
item = "Vegetable Pasta"
price = 12.99
print(f"You ordered: {item} - ${price}")
case 4:
item = "Chocolate Cake"
price = 6.99
print(f"You ordered: {item} - ${price}")
print("Order submitted to kitchen")Output:
You ordered: Vegetable Pasta - $12.99
Order submitted to kitchenContoh ini menunjukkan bagaimana setiap case dapat berisi beberapa statement. Saat menu_choice cocok dengan 3, Python mengeksekusi ketiga baris di blok case tersebut: menetapkan item, menetapkan price, dan mencetak konfirmasi pesanan.
13.2) Menggunakan Wildcard _, Literal Patterns, dan Multiple Patterns
13.2.1) Wildcard Pattern: Menangkap Semua Selainnya
Garis bawah _ adalah pattern khusus yang cocok dengan apa pun. Ini biasanya digunakan sebagai case terakhir untuk menangani semua nilai yang tidak cocok dengan pattern sebelumnya—mirip dengan klausa else terakhir pada rangkaian if-elif-else:
# Handler kode status HTTP dengan case default
status_code = 403
match status_code:
case 200:
print("Success: Request completed")
case 404:
print("Error: Page not found")
case 500:
print("Error: Server error")
case _:
print(f"Unhandled status code: {status_code}")Output:
Unhandled status code: 403Pattern _ berperan sebagai penangkap semua. Karena 403 tidak cocok dengan case spesifik mana pun, pattern wildcard cocok dan mengeksekusi bloknya. Pattern wildcard akan cocok dengan nilai apa pun, jadi sebaiknya selalu diletakkan paling akhir—case apa pun setelahnya tidak akan pernah dieksekusi.
Berikut alasan wildcard berguna dalam praktik:
# Penjadwal hari dalam seminggu
day = "Saturday"
match day:
case "Monday":
print("Team meeting at 9 AM")
case "Wednesday":
print("Project review at 2 PM")
case "Friday":
print("Weekly report due")
case _:
print(f"{day}: No scheduled events")Output:
Saturday: No scheduled eventsTanpa wildcard pattern, jika day adalah "Saturday", "Sunday", atau nilai lainnya, statement match akan selesai diam-diam tanpa output. Wildcard memastikan kamu menangani kasus yang tidak terduga atau tidak ditentukan dengan elegan.
13.2.2) Literal Patterns: Mencocokkan Nilai Spesifik
Literal pattern mencocokkan nilai yang persis sama. Kita sudah menggunakannya—angka, string, dan nilai boolean semuanya adalah literal pattern:
# Pengendali lampu lalu lintas
light_color = "yellow"
match light_color:
case "green":
print("Go")
case "yellow":
print("Caution: Light changing soon")
case "red":
print("Stop")
case _:
print("Invalid light color")Output:
Caution: Light changing soonKamu bisa menggunakan literal pattern dari berbagai tipe, dan match membandingkan baik nilai maupun tipenya:
# Validator konfigurasi (menggunakan tipe literal yang berbeda)
setting_value = True
match setting_value:
case True: # literal boolean
print("Feature enabled")
case False: # literal boolean
print("Feature disabled")
case None: # literal None
print("Feature not configured")
case 0: # literal integer
print("Feature explicitly turned off")
case "auto": # literal string
print("Feature set to automatic mode")
case _:
print("Invalid configuration value")Output:
Feature enabledLiteral pattern bekerja dengan integer, float, string, boolean, dan None. Python mengecek kesetaraan menggunakan aturan yang sama seperti operator ==.
13.2.3) Multiple Patterns dengan Operator OR
Terkadang kamu ingin mengeksekusi kode yang sama untuk beberapa nilai yang berbeda. Kamu bisa menggabungkan beberapa pattern menggunakan operator | (pipe), yang berarti "atau":
# Pendeteksi akhir pekan
day = "Saturday"
match day:
case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday":
print("It's a weekday - time to work!")
case "Saturday" | "Sunday":
print("It's the weekend - time to relax!")
case _:
print("Invalid day name")Output:
It's the weekend - time to relax!Operator | memungkinkan kamu menentukan beberapa pattern yang harus memicu aksi yang sama. Jika subject cocok dengan salah satu pattern yang dipisahkan oleh |, case tersebut dieksekusi. Ini jauh lebih rapi daripada menulis case terpisah dengan blok kode yang identik.
Kamu bisa mencampur berbagai tipe pattern dengan |:
# Validator input untuk pertanyaan ya/tidak
response = "yes"
match response:
case True | "yes":
print("You confirmed the action")
case False | "no":
print("You cancelled the action")
case _:
print("Please answer yes or no")Output:
You confirmed the action13.2.4) Menangkap Alternatif Mana yang Cocok dengan as
Saat menggunakan multiple pattern dengan |, kamu mungkin ingin tahu nilai spesifik mana yang cocok. Kamu bisa menggunakan keyword as untuk menangkap nilai yang cocok:
# Handler kode status dengan respons yang dikelompokkan
status = 201
match status:
case 200 | 201 | 202 | 204 as success_code:
print(f"Success: {success_code}")
case 400 | 401 | 403 | 404 as client_error:
print(f"Client error: {client_error}")
case 500 | 502 | 503 as server_error:
print(f"Server error: {server_error}")
case _:
print("Unknown status code")Output:
Success: 201Keyword as membuat variabel binding yang menangkap alternatif mana pun yang cocok. Dalam contoh ini, success_code terikat ke 201 karena itulah nilai spesifik yang cocok dari alternatif 200 | 201 | 202 | 204.
Berikut contoh lain yang menunjukkan bagaimana ini berguna untuk logging:
# Pemroses level log
log_level = "WARN"
match log_level:
case "DEBUG" | "TRACE" as level:
print(f"Verbose logging: {level}")
print("Detailed diagnostic information will be recorded")
case "INFO" | "NOTICE" as level:
print(f"Informational: {level}")
print("Normal operation messages will be recorded")
case "WARN" | "WARNING" as level:
print(f"Warning level: {level}")
print("Potential issues detected")
case "ERROR" | "FATAL" | "CRITICAL" as level:
print(f"Error level: {level}")
print("Immediate attention required")
case _:
print("Unknown log level")Output:
Warning level: WARN
Potential issues detected13.3) Mengekstrak Nilai dengan Binding Variables
13.3.1) Apa Itu Binding Variables?
Sejauh ini, kita mencocokkan terhadap nilai literal. Namun pattern matching menjadi benar-benar kuat ketika kamu bisa menangkap (capture) atau mengekstrak (extract) bagian dari data yang sedang kamu cocokkan. Binding variable (juga disebut capture pattern) adalah sebuah nama dalam pattern yang menangkap nilai yang cocok dan membuatnya tersedia di blok case.
Berikut contoh sederhana:
# Penangkapan nilai sederhana
command = "save"
match command:
case "quit":
print("Exiting program")
case action: # Ini adalah binding variable
print(f"Executing action: {action}")Output:
Executing action: savePattern action adalah binding variable. Ia cocok dengan nilai apa pun (seperti wildcard _), tetapi tidak seperti _, ia menangkap nilai tersebut dan menetapkannya ke nama action. Di dalam blok case, kamu bisa memakai action untuk merujuk ke nilai yang cocok.
Perbedaan penting: Binding variable mencocokkan apa pun, sama seperti _. Bedanya, _ membuang nilainya, sedangkan binding variable menangkapnya untuk digunakan di blok case.
13.3.2) Binding Variables vs Wildcards
Mari bandingkan binding variable dan wildcard secara langsung:
# Menggunakan wildcard - nilai tidak ditangkap
status = 403
match status:
case 200:
print("Success")
case _:
print("Some other status code") # Tidak bisa mengakses nilai sebenarnyaOutput:
Some other status codeSekarang dengan binding variable:
# Menggunakan binding variable - nilai ditangkap
status = 403
match status:
case 200:
print("Success")
case code: # Binding variable menangkap nilainya
print(f"Status code {code} received")Output:
Status code 403 receivedBinding variable code menangkap nilai 403, sehingga tersedia di dalam blok case. Ini berguna saat kamu perlu bekerja dengan nilai sebenarnya yang tidak cocok dengan pattern spesifik kamu.
13.3.3) Mencocokkan Tuple Patterns dan Mengekstrak Komponen
Pattern matching menjadi sangat kuat dengan data terstruktur seperti tuple. Kamu bisa mencocokkan bentuk tuple dan mengekstrak komponennya sekaligus. Walaupun kita akan mempelajari tuple secara detail di Bab 15, contoh ini hanya berfokus pada bagaimana tuple pattern bekerja dalam statement match.
# Sistem koordinat - mencocokkan tuple pattern
point = (3, 7)
match point:
case (0, 0):
print("Origin point")
case (0, y): # Cocok dengan titik mana pun pada sumbu y
print(f"On y-axis at y={y}")
case (x, 0): # Cocok dengan titik mana pun pada sumbu x
print(f"On x-axis at x={x}")
case (x, y): # Cocok dengan titik lainnya
print(f"Point at coordinates ({x}, {y})")Output:
Point at coordinates (3, 7)Mari uraikan apa yang terjadi:
- Subject
pointadalah tuple(3, 7) - Python mengecek setiap case pattern secara berurutan
- Tiga pattern pertama tidak cocok karena mensyaratkan nilai
0pada posisi tertentu, dan tuple(3, 7)tidak memiliki elemen yang sama dengan0 - Pattern
(x, y)cocok karena itu adalah tuple dengan dua elemen - Python mengikat
xke3danyke7 - Blok case dieksekusi dengan nilai yang ditangkap ini
Berikut contoh lain yang menunjukkan tuple pattern yang berbeda:
# Penganalisis warna RGB
color = (255, 0, 0)
match color:
case (0, 0, 0):
print("Black")
case (255, 255, 255):
print("White")
case (r, 0, 0): # Merah murni dengan intensitas bervariasi
print(f"Pure red with intensity {r}")
case (0, g, 0): # Hijau murni
print(f"Pure green with intensity {g}")
case (0, 0, b): # Biru murni
print(f"Pure blue with intensity {b}")
case (r, g, b): # Warna lainnya
print(f"RGB color: red={r}, green={g}, blue={b}")Output:
Pure red with intensity 255Input ini cocok dengan pattern (r, 0, 0) karena tuple memiliki tiga elemen, dua elemen terakhir adalah 0, dan nilai pertama terikat ke r.
13.3.4) Mencocokkan List Patterns
Kamu juga bisa mencocokkan list pattern dan mengekstrak elemen. Kita akan membahas list secara detail di Bab 14; untuk saat ini, contoh ini berfokus pada bagaimana list pattern bekerja dalam statement match:
# Perintah dengan argumen
command = ["move", "north", "5"]
match command:
case ["quit"]:
print("Exiting game")
case ["look"]:
print("You look around the room")
case ["move", direction]:
print(f"Moving {direction}")
case ["move", direction, distance]:
print(f"Moving {direction} for {distance} steps")
case _:
print("Unknown command")Output:
Moving north for 5 stepsPattern ["move", direction, distance] cocok dengan list tiga elemen di mana elemen pertama adalah "move". Ia menangkap elemen kedua sebagai direction dan elemen ketiga sebagai distance.
Berikut contoh praktis dengan panjang list yang bervariasi:
# Pemroses item keranjang belanja
item = ["laptop", 999.99, 2]
match item:
case [name]: # Item hanya dengan nama
print(f"Item: {name} (no price or quantity specified)")
case [name, price]: # Item dengan nama dan harga
print(f"Item: {name}, Price: ${price}, Quantity: 1 (default)")
case [name, price, quantity]: # Informasi item lengkap
total = price * quantity
print(f"Item: {name}, Price: ${price}, Quantity: {quantity}")
print(f"Subtotal: ${total}")
case _:
print("Invalid item format")Output:
Item: laptop, Price: $999.99, Quantity: 2
Subtotal: $1999.98Case [name, price, quantity] dieksekusi karena list memiliki tepat tiga elemen, dan setiap elemen terikat ke variabel yang sesuai.
13.3.5) Mencocokkan Dictionary Patterns
Pattern matching bekerja dengan dictionary juga, memungkinkan kamu mencocokkan key tertentu dan mengekstrak nilainya. Walaupun kita akan mempelajari dictionary secara detail di Bab 16, bagian ini hanya berfokus pada bagaimana dictionary pattern bekerja dalam statement match.
# Pemroses profil pengguna
user = {"name": "Alice", "role": "admin", "active": True}
match user:
case {"role": "admin", "active": True}:
print("Active administrator - full access granted")
case {"role": "admin", "active": False}:
print("Inactive administrator - access suspended")
case {"role": role, "active": True}: # Menangkap nilai role
print(f"Active user with role: {role}")
case {"role": role, "active": False}:
print(f"Inactive user with role: {role}")
case _:
print("Invalid user profile")Output:
Active administrator - full access grantedCase {"role": "admin", "active": True} dieksekusi karena dictionary pattern mengharuskan pencocokan pasangan key–value, dan kecocokan persis ini dicek sebelum pattern yang lebih umum.
Dictionary pattern bersifat fleksibel—ia cocok jika key yang ditentukan ada dengan nilai yang ditentukan, bahkan jika dictionary punya key tambahan:
# Handler respons API
response = {"status": "success", "data": {"id": 123, "name": "Product"}, "timestamp": "2025-12-17"}
match response:
case {"status": "error", "message": msg}:
print(f"Error occurred: {msg}")
case {"status": "success", "data": data}:
print(f"Success! Data received: {data}")
case _:
print("Unknown response format")Output:
Success! Data received: {'id': 123, 'name': 'Product'}Pattern {"status": "success", "data": data} cocok meskipun dictionary memiliki key "timestamp" tambahan. Pattern hanya mensyaratkan bahwa key yang ditentukan ada dengan nilai yang ditentukan (atau pattern).
13.3.6) Menggabungkan Literal dan Binding Variables
Kamu bisa mencampur literal pattern dan binding variable untuk membuat logika pencocokan yang canggih: Tidak seperti contoh tuple sebelumnya yang berfokus pada pencocokan struktur dan posisi, contoh ini menunjukkan bagaimana nilai literal dan binding variable bisa digabungkan untuk mengimplementasikan logika keputusan di dunia nyata.
# Router request HTTP
request = ("GET", "/api/users", 42)
match request:
case ("GET", "/", None):
print("Homepage request")
case ("GET", path, None):
print(f"GET request for: {path}")
case ("POST", path, data):
print(f"POST request to {path} with data: {data}")
case ("GET", path, user_id):
print(f"GET request for {path} with user ID: {user_id}")
case _:
print("Unsupported request type")Output:
GET request for /api/users with user ID: 42Contoh ini menunjukkan bagaimana kamu bisa mencocokkan nilai spesifik (seperti "GET") sekaligus menangkap yang lain (seperti path dan user_id) dalam pattern yang sama.
13.3.7) Contoh Praktis: Event Handler
Mari buat contoh lengkap yang menunjukkan kekuatan binding variable:
# Handler event game
event = ("player_move", {"x": 10, "y": 5, "speed": 2})
match event:
case ("player_move", {"x": x, "y": y}):
print(f"Player moved to position ({x}, {y})")
case ("player_attack", {"target": target, "damage": damage}):
print(f"Player attacked {target} for {damage} damage")
case ("item_pickup", {"item": item_name}):
print(f"Player picked up: {item_name}")
case ("game_over", {"score": final_score}):
print(f"Game ended. Final score: {final_score}")
case (event_type, data):
print(f"Unknown event type: {event_type}")
print(f"Event data: {data}")Output:
Player moved to position (10, 5)Event handler ini mencocokkan tuple yang berisi tipe event dan dictionary data event. Ia mengekstrak nilai tertentu dari dictionary berdasarkan tipe event, sehingga mudah memproses berbagai jenis event dengan kode yang rapi dan mudah dibaca.
13.4) Menambahkan Kondisi Ekstra dengan if Guard
13.4.1) Apa Itu Guard?
Terkadang kamu perlu mencocokkan sebuah pattern dan mengecek kondisi tambahan. If guard adalah kondisi ekstra yang bisa kamu tambahkan ke sebuah case pattern menggunakan keyword if. Case hanya cocok jika pattern cocok dan kondisi guard bernilai true.
Berikut sintaksnya:
match subject:
case pattern if condition:
# Kode dieksekusi hanya jika pattern cocok DAN condition bernilai trueMari lihat contoh sederhana:
# Kontrol akses berdasarkan usia
age = 16
match age:
case age if age >= 18:
print("Adult - full access granted")
case age if age >= 13:
print("Teen - limited access granted")
case age if age >= 0:
print("Child - parental supervision required")
case _:
print("Invalid age")Output:
Teen - limited access grantedDalam contoh ini, binding variable age menangkap nilainya, dan guard if age >= 13 menambahkan kondisi tambahan. Case hanya cocok jika nilainya 13 atau lebih besar. Karena age adalah 16, case kedua cocok dan dieksekusi.
13.4.2) Bagaimana Guard Dievaluasi
Memahami urutan evaluasi itu penting. Berikut visualisasi detail yang menunjukkan bagaimana guard berinteraksi dengan pattern matching:
Python pertama-tama mengecek apakah pattern cocok. Hanya jika pattern cocok, Python mengevaluasi kondisi guard. Jika guard bernilai false, Python lanjut ke case berikutnya—meskipun pattern tadi cocok.
Berikut contoh yang mendemonstrasikan ini:
# Sistem peringatan suhu
temperature = 25
match temperature:
case temp if temp > 35:
print(f"Extreme heat warning: {temp}°C")
case temp if temp > 30:
print(f"High temperature alert: {temp}°C")
case temp if temp > 20:
print(f"Comfortable temperature: {temp}°C")
case temp if temp > 10:
print(f"Cool temperature: {temp}°C")
case temp:
print(f"Cold temperature: {temp}°C")Output:
Comfortable temperature: 25°CSetiap case menggunakan binding variable temp untuk menangkap nilai suhu, lalu menerapkan guard untuk mengecek apakah nilainya berada dalam rentang tertentu. Case dicek secara berurutan, jadi case pertama yang cocok dengan guard bernilai true akan dieksekusi.
13.4.3) Guard dengan Literal Patterns
Kamu bisa menggabungkan guard dengan literal pattern untuk membuat pencocokan yang lebih spesifik:
# Kalkulator diskon berdasarkan tipe item dan jumlah
item = ("book", 5)
match item:
case ("book", quantity) if quantity >= 10:
discount = 0.20 # Diskon 20% untuk 10+ buku
print(f"Bulk book order: {quantity} books, {discount*100}% discount")
case ("book", quantity) if quantity >= 5:
discount = 0.10 # Diskon 10% untuk 5-9 buku
print(f"Book order: {quantity} books, {discount*100}% discount")
case ("book", quantity):
discount = 0.0 # Tidak ada diskon untuk kurang dari 5 buku
print(f"Book order: {quantity} books, no discount")
case (item_type, quantity):
print(f"Order: {quantity} {item_type}(s)")Output:
Book order: 5 books, 10.0% discountPattern ("book", quantity) cocok dengan tuple di mana elemen pertama adalah "book". Guard if quantity >= 5 menambahkan kondisi bahwa jumlah harus minimal 5.
13.4.4) Guard dengan Kondisi Kompleks
Guard bisa menggunakan ekspresi boolean apa pun, termasuk kondisi kompleks dengan and, or, dan not:
# Evaluator nilai siswa dengan mempertimbangkan kehadiran
student = {"name": "Bob", "grade": 85, "attendance": 75}
match student:
case {"grade": g, "attendance": a} if g >= 90 and a >= 90:
status = "Excellent"
print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
case {"grade": g, "attendance": a} if g >= 80 and a >= 80:
status = "Good"
print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
case {"grade": g, "attendance": a} if g >= 70 and a >= 70:
status = "Satisfactory"
print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
case {"grade": g, "attendance": a} if g >= 60 or a >= 60:
status = "Needs Improvement"
print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
case _:
print("Failing - immediate intervention required")Output:
Grade: 85, Attendance: 75% - Status: SatisfactoryGuard if g >= 70 and a >= 70 mengharuskan nilai dan kehadiran minimal 70. Karena Bob memiliki nilai 85 dan kehadiran 75%, case ini cocok.
13.4.5) Contoh Praktis: Sistem Autentikasi Pengguna
Mari buat contoh lengkap yang menggunakan guard untuk mengimplementasikan sistem autentikasi yang realistis:
# Autentikasi pengguna dengan akses berbasis peran
user = {"username": "alice", "role": "admin", "active": True, "login_attempts": 0}
match user:
case {"active": False}:
print("Account suspended - contact administrator")
case {"login_attempts": attempts} if attempts >= 3:
print("Account locked due to too many failed login attempts")
case {"role": "admin", "active": True}:
print("Admin access granted - full system privileges")
case {"role": "moderator", "active": True}:
print("Moderator access granted - content management privileges")
case {"role": role, "active": True} if role in ["editor", "author"]:
print(f"{role.capitalize()} access granted - content creation privileges")
case {"role": "user", "active": True}:
print("User access granted - basic privileges")
case _:
print("Access denied - invalid user profile")Output:
Admin access granted - full system privilegesContoh ini menunjukkan bagaimana guard dapat mengimplementasikan logika bisnis yang kompleks. Sistem mengecek beberapa kondisi: status akun, percobaan login, dan izin berbasis peran. Setiap case menangani skenario tertentu, membuat logika autentikasi jelas dan mudah dipelihara.
13.5) Mencocokkan Bentuk Sequence dan Mapping Sederhana
13.5.1) Mencocokkan Sequence dengan Panjang Variabel
Terkadang kamu perlu mencocokkan sequence dengan panjang yang bervariasi. Pattern matching Python mendukung ini dengan operator *, yang menangkap nol atau lebih elemen.
# Parser perintah dengan argumen variabel
command = ["copy", "file1.txt", "file2.txt", "file3.txt", "backup/"]
match command:
case ["help"]:
print("Available commands: copy, move, delete")
case ["copy", source, destination]:
print(f"Copying {source} to {destination}")
case ["copy", *sources, destination]:
print(f"Copying {len(sources)} files to {destination}")
print(f"Source files: {sources}")
case ["delete", *files]:
print(f"Deleting {len(files)} file(s): {files}")
case _:
print("Unknown command")Output:
Copying 3 files to backup/
Source files: ['file1.txt', 'file2.txt', 'file3.txt']Pattern ["copy", *sources, destination] cocok dengan list yang diawali "copy", diakhiri dengan tujuan, dan memiliki sejumlah file sumber di tengahnya. *sources menangkap semua elemen di tengah sebagai sebuah list.
Penting: Kamu hanya bisa menggunakan satu pattern * per sequence pattern, dan ia menangkap elemen sebagai list:
# Parser entri log
log_entry = ["2025-12-17", "10:30:45", "ERROR", "Database", "connection", "timeout"]
match log_entry:
case [date, time, "ERROR", *error_details]:
print(f"Error on {date} at {time}")
print(f"Error details: {' '.join(error_details)}")
case [date, time, "WARNING", *warning_details]:
print(f"Warning on {date} at {time}")
print(f"Warning details: {' '.join(warning_details)}")
case [date, time, level, *message]:
print(f"{level} on {date} at {time}: {' '.join(message)}")Output:
Error on 2025-12-17 at 10:30:45
Error details: Database connection timeout13.5.2) Menggabungkan Sequence Patterns dengan Guard
Kamu bisa menggunakan guard dengan sequence pattern untuk menambahkan kondisi tambahan:
# Penganalisis daftar nilai
grades = [85, 92, 78, 95, 88]
match grades:
case []:
print("No grades recorded")
case [grade] if grade >= 90:
print(f"Single excellent grade: {grade}")
case [grade] if grade < 60:
print(f"Single failing grade: {grade}")
case [*all_grades] if len(all_grades) >= 5 and sum(all_grades) / len(all_grades) >= 90:
average = sum(all_grades) / len(all_grades)
print(f"Excellent performance! Average: {average:.1f}")
case [*all_grades] if len(all_grades) >= 5:
average = sum(all_grades) / len(all_grades)
print(f"Performance review: {len(all_grades)} grades, Average: {average:.1f}")
case [*all_grades]:
print(f"Insufficient data: only {len(all_grades)} grade(s)")Output:
Performance review: 5 grades, Average: 87.6Pattern [*all_grades] menangkap semua elemen dalam list, dan guard mengecek panjang sekaligus menghitung rata-rata untuk menentukan pesan yang sesuai.
Pattern matching dengan match dan case menyediakan cara yang kuat dan ekspresif untuk menangani pengambilan keputusan yang kompleks di Python. Dari pencocokan nilai sederhana hingga pola struktural yang canggih dengan guard, fitur ini memungkinkan kamu menulis kode yang lebih rapi dan lebih mudah dipelihara untuk menangani banyak kasus dan mengekstrak data dari struktur yang kompleks.
Seiring kamu terus belajar Python, kamu akan menemukan bahwa pattern matching melengkapi logika kondisional yang kamu pelajari di Bab 8, menawarkan alternatif yang elegan saat berurusan dengan banyak kasus yang berbeda, terutama saat bekerja dengan data terstruktur. Kuncinya adalah memilih alat yang tepat untuk setiap situasi: gunakan if-elif-else untuk kondisi sederhana dan logika boolean, dan gunakan match-case saat kamu mengecek satu nilai terhadap banyak kemungkinan atau bekerja dengan data terstruktur yang membutuhkan ekstraksi berbasis pattern.