Python match case

Python 3.10 引入了 match 語句,類似於其他語言的 switch,但功能更強大,支援結構化模式比對 (structural pattern matching)。

基本語法

match 變數:
    case 模式1:
        # 匹配時執行
    case 模式2:
        # 匹配時執行
    case _:
        # 預設情況(都不匹配時)
status = 404

match status:
    case 200:
        print("OK")
    case 404:
        print("Not Found")
    case 500:
        print("Internal Server Error")
    case _:
        print("Unknown status")

輸出:

Not Found
_ 是萬用字元,匹配任何值,類似於其他語言的 default

匹配多個值

使用 | 匹配多個值:

status = 301

match status:
    case 200 | 201 | 202:
        print("Success")
    case 301 | 302:
        print("Redirect")
    case 400 | 401 | 403 | 404:
        print("Client Error")
    case 500 | 502 | 503:
        print("Server Error")
    case _:
        print("Unknown")

匹配序列

point = (0, 1)

match point:
    case (0, 0):
        print("Origin")
    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})")

輸出:

On Y-axis at y=1

匹配不定長度序列

numbers = [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}")

輸出:

First: 1, Rest: [2, 3, 4, 5]

匹配字典

data = {"action": "create", "name": "Alice"}

match data:
    case {"action": "create", "name": name}:
        print(f"Creating user: {name}")
    case {"action": "delete", "id": user_id}:
        print(f"Deleting user with id: {user_id}")
    case {"action": action}:
        print(f"Unknown action: {action}")
    case _:
        print("Invalid data")

輸出:

Creating user: Alice

加上條件 (Guard)

使用 if 加上額外條件:

point = (3, 4)

match point:
    case (x, y) if x == y:
        print(f"On diagonal at ({x}, {y})")
    case (x, y) if x > 0 and y > 0:
        print(f"In first quadrant at ({x}, {y})")
    case (x, y):
        print(f"At ({x}, {y})")

輸出:

In first quadrant at (3, 4)

匹配物件

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

point = Point(0, 5)

match point:
    case Point(x=0, y=0):
        print("Origin")
    case Point(x=0, y=y):
        print(f"On Y-axis at {y}")
    case Point(x=x, y=0):
        print(f"On X-axis at {x}")
    case Point(x=x, y=y):
        print(f"Point at ({x}, {y})")

匹配型別

def process(value):
    match value:
        case str():
            print(f"String: {value}")
        case int() | float():
            print(f"Number: {value}")
        case list():
            print(f"List with {len(value)} items")
        case dict():
            print(f"Dict with {len(value)} keys")
        case _:
            print(f"Unknown type: {type(value)}")

process("hello")   # String: hello
process(42)        # Number: 42
process([1, 2, 3]) # List with 3 items

使用 as 綁定變數

data = [1, 2, 3]

match data:
    case [1, *rest] as full_list:
        print(f"Starts with 1, rest: {rest}, full: {full_list}")

輸出:

Starts with 1, rest: [2, 3], full: [1, 2, 3]

實際範例

解析指令

def handle_command(command):
    match command.split():
        case ["quit" | "exit"]:
            return "Goodbye!"
        case ["hello", name]:
            return f"Hello, {name}!"
        case ["add", *numbers]:
            return f"Sum: {sum(int(n) for n in numbers)}"
        case ["help"]:
            return "Available commands: quit, hello <name>, add <numbers...>"
        case _:
            return "Unknown command"

print(handle_command("hello Alice"))  # Hello, Alice!
print(handle_command("add 1 2 3 4"))  # Sum: 10
print(handle_command("quit"))         # Goodbye!

處理 API 回應

def handle_response(response):
    match response:
        case {"status": "success", "data": data}:
            print(f"Success! Data: {data}")
        case {"status": "error", "message": msg}:
            print(f"Error: {msg}")
        case {"status": status}:
            print(f"Unknown status: {status}")
        case _:
            print("Invalid response format")

handle_response({"status": "success", "data": [1, 2, 3]})
handle_response({"status": "error", "message": "Not found"})

簡單計算機

def calculate(expression):
    match expression:
        case ("+", a, b):
            return a + b
        case ("-", a, b):
            return a - b
        case ("*", a, b):
            return a * b
        case ("/", a, b) if b != 0:
            return a / b
        case ("/", _, 0):
            return "Error: Division by zero"
        case _:
            return "Invalid expression"

print(calculate(("+", 5, 3)))   # 8
print(calculate(("*", 4, 7)))   # 28
print(calculate(("/", 10, 0)))  # Error: Division by zero