Match-Case Statement (Pattern Matching)
Match-Case là tính năng Pattern Matching được giới thiệu trong Python 3.10 (tháng 10/2021). Nó giống như switch-case trong các ngôn ngữ khác nhưng mạnh mẽ hơn nhiều.
1. Giới thiệu
Phần tiêu đề “1. Giới thiệu”Tại sao cần Match-Case?
Phần tiêu đề “Tại sao cần Match-Case?”Trước Python 3.10, để kiểm tra nhiều giá trị ta phải dùng if-elif-else:
# Cách cũ với if-elif-elsestatus_code = 404
if status_code == 200: message = "OK"elif status_code == 404: message = "Not Found"elif status_code == 500: message = "Internal Server Error"else: message = "Unknown"
print(message) # Not FoundVới Match-Case, code ngắn gọn và dễ đọc hơn:
# Python 3.10+ với match-casestatus_code = 404
match status_code: case 200: message = "OK" case 404: message = "Not Found" case 500: message = "Internal Server Error" case _: message = "Unknown"
print(message) # Not FoundCú pháp cơ bản
Phần tiêu đề “Cú pháp cơ bản”match giá_trị: case pattern_1: # Code khi match với pattern_1 case pattern_2: # Code khi match với pattern_2 case _: # Default case (wildcard)Lưu ý: _ là wildcard pattern (giống else hoặc default)
2. Match với giá trị đơn giản
Phần tiêu đề “2. Match với giá trị đơn giản”So khớp số
Phần tiêu đề “So khớp số”number = 2
match number: case 0: print("Zero") case 1: print("One") case 2: print("Two") # In ra dòng này case 3: print("Three") case _: print("Other number")So khớp chuỗi
Phần tiêu đề “So khớp chuỗi”command = "start"
match command: case "start": print("Starting...") # In ra dòng này case "stop": print("Stopping...") case "pause": print("Pausing...") case "resume": print("Resuming...") case _: print("Unknown command")So khớp nhiều giá trị (OR pattern)
Phần tiêu đề “So khớp nhiều giá trị (OR pattern)”day = "Saturday"
match day: case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday": print("Weekday") case "Saturday" | "Sunday": print("Weekend") # In ra dòng này case _: print("Invalid day")
# Ví dụ khácgrade = "B"
match grade: case "A" | "A+": print("Excellent") case "B" | "B+": print("Good") # In ra dòng này case "C" | "C+": print("Average") case "D" | "F": print("Poor") case _: print("Invalid grade")3. Match với Guards (Điều kiện bổ sung)
Phần tiêu đề “3. Match với Guards (Điều kiện bổ sung)”Guards cho phép thêm điều kiện if vào pattern:
age = 25
match age: case x if x < 0: print("Invalid age") case x if x < 18: print("Minor") case x if x < 60: print("Adult") # In ra dòng này case x if x >= 60: print("Senior") case _: print("Unknown")
# Ví dụ phức tạp hơnscore = 85
match score: case x if x >= 90: print("Grade: A") case x if 80 <= x < 90: print("Grade: B") # In ra dòng này case x if 70 <= x < 80: print("Grade: C") case x if 60 <= x < 70: print("Grade: D") case x if x < 60: print("Grade: F") case _: print("Invalid score")4. Match với Tuples và Lists
Phần tiêu đề “4. Match với Tuples và Lists”So khớp tuple
Phần tiêu đề “So khớp tuple”point = (0, 0)
match point: case (0, 0): print("Origin") # In ra dòng này case (0, y): print(f"On Y-axis at y={y}") case (x, 0): print(f"On X-axis at x={x}") case (x, y): print(f"Point at ({x}, {y})")
# Ví dụ kháccoordinate = (3, 4)
match coordinate: case (0, 0): print("Origin") case (x, 0): print(f"On X-axis at x={x}") case (0, y): print(f"On Y-axis at y={y}") case (x, y): print(f"Point at x={x}, y={y}") # In ra: Point at x=3, y=4So khớp list với độ dài cố định
Phần tiêu đề “So khớp list với độ dài cố định”rgb = [255, 0, 0]
match rgb: case [255, 0, 0]: print("Red") # In ra dòng này case [0, 255, 0]: print("Green") case [0, 0, 255]: print("Blue") case [r, g, b]: print(f"Custom color: R={r}, G={g}, B={b}")
# Ví dụ kháccolor = [128, 128, 128]
match color: case [255, 255, 255]: print("White") case [0, 0, 0]: print("Black") case [r, g, b]: print(f"Gray-ish: R={r}, G={g}, B={b}") # In ra dòng nàySo khớp list với độ dài thay đổi
Phần tiêu đề “So khớp list với độ dài thay đổi”# Sử dụng * để capture phần còn lạinumbers = [1, 2, 3, 4, 5]
match numbers: case []: print("Empty list") case [x]: print(f"Single element: {x}") case [x, y]: print(f"Two elements: {x}, {y}") case [first, *rest]: print(f"First: {first}, Rest: {rest}") # In ra: First: 1, Rest: [2, 3, 4, 5]
# Ví dụ khácdata = [1, 2, 3]
match data: case [x, *middle, y]: print(f"First: {x}, Middle: {middle}, Last: {y}") # In ra: First: 1, Middle: [2], Last: 3
# Bắt phần đầu và cuốiitems = ["apple", "banana", "cherry", "date"]
match items: case [first, second, *rest]: print(f"First two: {first}, {second}") print(f"Rest: {rest}") # In ra: # First two: apple, banana # Rest: ['cherry', 'date']5. Match với Dictionary
Phần tiêu đề “5. Match với Dictionary”user = {"name": "John", "role": "admin"}
match user: case {"role": "admin"}: print("Admin user") # In ra dòng này case {"role": "user"}: print("Regular user") case {"role": "guest"}: print("Guest user") case _: print("Unknown role")
# Capture giá trịperson = {"name": "Alice", "age": 25, "city": "NYC"}
match person: case {"name": name, "age": age} if age >= 18: print(f"{name} is an adult") # In ra: Alice is an adult case {"name": name, "age": age}: print(f"{name} is a minor")
# Dictionary với pattern phức tạpdata = {"type": "user", "id": 123, "name": "Bob"}
match data: case {"type": "user", "id": user_id, "name": user_name}: print(f"User: {user_name} (ID: {user_id})") # In ra: User: Bob (ID: 123) case {"type": "admin", "id": admin_id}: print(f"Admin ID: {admin_id}") case _: print("Unknown data type")6. Match với Class Instances
Phần tiêu đề “6. Match với Class Instances”Định nghĩa class
Phần tiêu đề “Định nghĩa class”class Point: def __init__(self, x, y): self.x = x self.y = y
class Circle: def __init__(self, center, radius): self.center = center self.radius = radius
class Rectangle: def __init__(self, width, height): self.width = width self.height = heightPattern matching với objects
Phần tiêu đề “Pattern matching với objects”# Tạo objectsp1 = Point(0, 0)p2 = Point(3, 4)c1 = Circle(Point(0, 0), 5)r1 = Rectangle(10, 20)
# Match với Pointmatch p1: case Point(x=0, y=0): print("Origin point") # In ra dòng này case Point(x=0, y=y): print(f"On Y-axis at y={y}") case Point(x=x, y=0): print(f"On X-axis at x={x}") case Point(x=x, y=y): print(f"Point at ({x}, {y})")
# Match với Circlematch c1: case Circle(center=Point(x=0, y=0), radius=r): print(f"Circle at origin with radius {r}") # In ra: Circle at origin with radius 5 case Circle(center=Point(x=x, y=y), radius=r): print(f"Circle at ({x}, {y}) with radius {r}")
# Match với Rectanglematch r1: case Rectangle(width=w, height=h) if w == h: print(f"Square with side {w}") case Rectangle(width=w, height=h): print(f"Rectangle {w}x{h}") # In ra: Rectangle 10x207. Ví dụ thực tế
Phần tiêu đề “7. Ví dụ thực tế”HTTP Status Code Handler
Phần tiêu đề “HTTP Status Code Handler”def handle_response(status_code): match status_code: case 200: return "OK - Success" case 201: return "Created" case 204: return "No Content" case 400: return "Bad Request" case 401: return "Unauthorized" case 403: return "Forbidden" case 404: return "Not Found" case 500: return "Internal Server Error" case code if 200 <= code < 300: return f"Success ({code})" case code if 400 <= code < 500: return f"Client Error ({code})" case code if 500 <= code < 600: return f"Server Error ({code})" case _: return "Unknown Status"
print(handle_response(200)) # OK - Successprint(handle_response(404)) # Not Foundprint(handle_response(503)) # Server Error (503)Command Parser
Phần tiêu đề “Command Parser”def parse_command(command): match command.split(): case ["quit"] | ["exit"]: print("Exiting program...") return True
case ["help"]: print("Available commands: quit, help, echo, add, greet")
case ["echo", *words]: print(" ".join(words))
case ["add", x, y]: try: result = int(x) + int(y) print(f"{x} + {y} = {result}") except ValueError: print("Invalid numbers")
case ["greet", name]: print(f"Hello, {name}!")
case _: print("Unknown command. Type 'help' for available commands.")
return False
# Sử dụngparse_command("help") # Available commands: ...parse_command("echo Hello World") # Hello Worldparse_command("add 5 3") # 5 + 3 = 8parse_command("greet Alice") # Hello, Alice!JSON API Response Handler
Phần tiêu đề “JSON API Response Handler”def process_api_response(response): match response: case {"status": "success", "data": data}: print(f"Success! Data: {data}")
case {"status": "error", "message": msg, "code": code}: print(f"Error {code}: {msg}")
case {"status": "error", "message": msg}: print(f"Error: {msg}")
case {"status": "pending", "task_id": task_id}: print(f"Task {task_id} is pending...")
case {"status": status}: print(f"Unknown status: {status}")
case _: print("Invalid response format")
# Testprocess_api_response({"status": "success", "data": {"id": 1, "name": "John"}})# Success! Data: {'id': 1, 'name': 'John'}
process_api_response({"status": "error", "message": "Not found", "code": 404})# Error 404: Not found
process_api_response({"status": "pending", "task_id": "abc123"})# Task abc123 is pending...Shape Calculator
Phần tiêu đề “Shape Calculator”class Circle: def __init__(self, radius): self.radius = radius
class Rectangle: def __init__(self, width, height): self.width = width self.height = height
class Triangle: def __init__(self, base, height): self.base = base self.height = height
def calculate_area(shape): import math
match shape: case Circle(radius=r): area = math.pi * r ** 2 return f"Circle area: {area:.2f}"
case Rectangle(width=w, height=h): area = w * h return f"Rectangle area: {area:.2f}"
case Triangle(base=b, height=h): area = 0.5 * b * h return f"Triangle area: {area:.2f}"
case _: return "Unknown shape"
# Testprint(calculate_area(Circle(5))) # Circle area: 78.54print(calculate_area(Rectangle(4, 6))) # Rectangle area: 24.00print(calculate_area(Triangle(8, 5))) # Triangle area: 20.00Game Move Handler
Phần tiêu đề “Game Move Handler”def handle_move(move): match move: case ("go", direction) if direction in ["north", "south", "east", "west"]: print(f"Moving {direction}")
case ("take", item): print(f"Taking {item}")
case ("drop", item): print(f"Dropping {item}")
case ("use", item, "on", target): print(f"Using {item} on {target}")
case ("attack", enemy): print(f"Attacking {enemy}")
case ("inventory",): print("Showing inventory")
case _: print("Invalid move")
# Testhandle_move(("go", "north")) # Moving northhandle_move(("take", "sword")) # Taking swordhandle_move(("use", "key", "on", "door")) # Using key on doorhandle_move(("inventory",)) # Showing inventory8. So sánh với if-elif-else
Phần tiêu đề “8. So sánh với if-elif-else”Khi nào dùng Match-Case?
Phần tiêu đề “Khi nào dùng Match-Case?”✅ NÊN dùng Match-Case khi:
- Kiểm tra nhiều giá trị cụ thể
- Pattern matching phức tạp (tuples, lists, dicts)
- Destructuring dữ liệu
- Code dễ đọc và maintain hơn
# ✅ TỐT với Match-Casematch point: case (0, 0): print("Origin") case (0, y): print(f"Y-axis at {y}") case (x, 0): print(f"X-axis at {x}") case (x, y): print(f"Point ({x}, {y})")❌ KHÔNG nên dùng Match-Case khi:
- Chỉ có 1-2 điều kiện đơn giản
- Điều kiện phức tạp với nhiều logic operators
- Python version < 3.10
# ❌ KHÔNG TỐT - Quá đơn giản, dùng if tốt hơnmatch age >= 18: case True: print("Adult") case False: print("Minor")
# ✅ TỐT - Dùng ifif age >= 18: print("Adult")else: print("Minor")9. Lưu ý quan trọng
Phần tiêu đề “9. Lưu ý quan trọng”Python version
Phần tiêu đề “Python version”# Match-case CHỈ hoạt động từ Python 3.10+import sys
if sys.version_info >= (3, 10): print("Match-case is supported!")else: print("Please upgrade to Python 3.10+")Không có fall-through
Phần tiêu đề “Không có fall-through”Không giống C/Java, Python match-case KHÔNG có fall-through. Chỉ một case được thực thi.
# Python match-case không cần 'break'number = 2
match number: case 1: print("One") case 2: print("Two") # Chỉ in dòng này, dừng ngay case 3: print("Three")Wildcard pattern (_)
Phần tiêu đề “Wildcard pattern (_)”# _ match mọi giá trị (nên đặt cuối cùng)value = 100
match value: case 1 | 2 | 3: print("Small") case _: print("Other") # In ra dòng nàyTổng kết
Phần tiêu đề “Tổng kết”- Match-Case là Pattern Matching trong Python 3.10+
- Mạnh mẽ hơn switch-case truyền thống
- Hỗ trợ:
- So khớp giá trị đơn giản
- OR patterns với
| - Guards với
if - Destructuring: tuples, lists, dicts
- Class instances
- Wildcard
_
- Không có fall-through - chỉ một case được thực thi
- Làm code ngắn gọn, dễ đọc hơn if-elif-else trong nhiều trường hợp
- Đặc biệt hữu ích khi làm việc với structured data (API responses, commands, shapes, etc.)