match(3.10+)是结构模式匹配而非 switch:模式可以解构序列、映射与对象,并把子部件绑定为变量。

字面模式与捕获模式

def handle(cmd: str) -> str:
    match cmd.split():
        case ["quit"]:
            return "退出"
        case ["go", direction]:        # "go" 是字面模式,direction 是捕获模式
            return f"前往 {direction}"
        case _:
            return "未知命令"

关键区别:小写裸名是捕获模式(总是匹配并绑定新变量),不是值比较。想匹配常量必须用限定名:

match color:
    case RED:        # ❌ 捕获:把 color 绑定为 RED,永远匹配成功
        ...
    case Color.RED:  # ✅ 带点号的属性访问才是字面比较
        ...

序列与映射模式

match data:
    case [x, y]:            # 恰好两个元素,解包绑定
        ...
    case [first, *rest]:    # 星号解包,任意长度
        ...
    case [_, _, _]:         # 通配符占位:恰好三个元素、不关心内容
        ...
    case {"type": "point", "x": x, "y": y}:   # 含这些键即匹配,允许额外键
        ...

序列模式匹配任何实现序列协议的对象(list/tuple 等,见 数据模型与内建序列);str 和 bytes 不算,避免误伤字符串分支。

类模式与 match_args

from dataclasses import dataclass
 
@dataclass
class Point:
    x: int
    y: int
 
match p:
    case Point(0, 0):         # 位置模式:按 __match_args__ 顺序匹配字段
        print("原点")
    case Point(x, y) if x == y:   # 守卫可引用已绑定的变量
        print("对角线")
    case Point(x=0, y=y):     # 关键字模式:按字段名匹配
        print(f"在 y 轴上, y={y}")

数据类 dataclass 自动生成 __match_args__ = ("x", "y"),天然支持位置类模式;普通类需自行定义该类属性。

或模式与守卫

ALLOWED = {"run", "walk"}
 
match cmd:
    case ["drop" | "discard", item]:     # | 组合多个字面量
        drop(item)
    case [action] if action in ALLOWED:  # 模式匹配成功后再判断守卫
        run(action)
    case _:
        pass

守卫失败时不算匹配,继续尝试下一个 case;模式先于守卫求值,守卫里可使用该模式绑定的变量。

常见误区

  • 首个匹配的 case 即结束,不写 break;case 体也不能为空
  • _ 是通配符不绑定值,case _: 必须放在最后
  • 匹配只看”形似”:序列模式允许通配、映射模式忽略多余键——需要严格结构校验就在守卫里补