match / case 语句

该用法在 Python3.10+ 加入

1
2
3
4
5
6
7
match <subject>:
case <pattern1>:
<statements1>
case <pattern2>:
<statements2>
case _:
<default_statements>
  • match:开始匹配语句。
  • <subject>:要进行匹配的值(类似 switch 的“输入值”)。
  • case:每个分支的匹配模式。
  • _:通配符,表示 “任意匹配”(类似 default)。
  • 匹配成功后只执行第一个符合的 case,不会自动贯穿(即不需要 break)。

基本概念

传统 if-elif 判断是布尔逻辑,而 match/case结构解构 + 匹配

例如:

1
2
3
4
5
6
7
match x:
case 0:
print("zero")
case 1:
print("one")
case _:
print("other")

看似是 switch,但实际上 case 模式能“解构”更复杂的数据结构,如:

  • 序列 / 元组 / 字典
  • 带属性类实例
  • 带类型约束
  • 具名元组 / dataclass / 自定义类

匹配类型与模式种类

Python 模式匹配支持多种模式类型:

模式类型 示例 说明
常量模式 case 1: 与具体值匹配
通配符模式 case _: 匹配任意值
捕获模式 case x: 匹配任意值并绑定到变量 x
序列模式 case [a, b]: 匹配长度相同的序列并解构
映射模式 case {"x": x, "y": y}: 匹配字典并提取键值
类模式 case Point(x, y): 匹配类实例并解构字段
守卫模式(条件匹配) case pattern if condition: 匹配后再判断附加条件
OR 模式(联合匹配) case 0 | 1 | 2: 任意一个匹配即成功

详细讲解每种模式

常量模式

1
2
3
4
5
6
7
match command:
case "start":
print("Starting...")
case "stop":
print("Stopping...")
case _:
print("Unknown command")

简单、清晰,相当于 switch-case。

捕获模式

1
2
3
match data:
case x:
print(f"Got value: {x}")

这会匹配任意值并绑定到 x
注意:如果想匹配变量名本身的值,而不是绑定新变量,必须使用 value 前加点号:

1
2
3
4
value = 42
match x:
case .value: # 匹配变量 value 的值,而不是新绑定
print("Matched 42!")

序列模式

可以匹配解构序列的结构:

1
2
3
4
5
6
7
match [1, 2, 3]:
case [1, 2, 3]:
print("Exact match")
case [1, 2, _]:
print("Third can be anything")
case [1, *rest]:
print("Starts with 1")

*rest 表示剩余元素(类似可变参数)。

还可以嵌套:

1
2
3
match [1, [2, 3]]:
case [1, [x, y]]:
print(x, y) # 输出 2 3

映射模式

用于匹配字典结构:

1
2
3
4
5
match {"x": 1, "y": 2, "z": 3}:
case {"x": x, "y": y}:
print(f"x={x}, y={y}")
case {"z": z}:
print(f"only z={z}")

还可以使用 **rest 捕获剩余键:

1
2
3
match data:
case {"id": id, **others}:
print(f"id={id}, rest={others}")

类模式

可以匹配对象的类型和属性:

1
2
3
4
5
6
7
8
9
10
11
12
class Point:
def __init__(self, x, y):
self.x = x
self.y = y

p = Point(1, 2)

match p:
case Point(x=0, y=0):
print("Origin")
case Point(x, y):
print(f"Point({x}, {y})")

可以使用带类型的匹配:

1
2
3
4
5
match value:
case int():
print("Integer")
case str():
print("String")

守卫模式(条件匹配)

在模式后加上 if 条件,进一步限制:

1
2
3
4
5
6
7
match x:
case int(n) if n > 0:
print("Positive int")
case int(n) if n < 0:
print("Negative int")
case _:
print("Zero or not int")

OR 模式(联合匹配)

可以在一个 case 中匹配多个模式:

1
2
3
4
5
6
7
match command:
case "start" | "run" | "go":
print("Executing start-like command")
case "stop" | "halt":
print("Stopping")
case _:
print("Unknown")

应用示例

综合示例:抽象语法树匹配

模式匹配非常适合解析树形结构(如语法树):

1
2
3
4
5
6
7
8
9
10
11
12
13
def eval_expr(expr):
match expr:
case ("num", value):
return value
case ("add", left, right):
return eval_expr(left) + eval_expr(right)
case ("mul", left, right):
return eval_expr(left) * eval_expr(right)
case _:
raise ValueError("Unknown expression")

tree = ("add", ("num", 2), ("mul", ("num", 3), ("num", 4)))
print(eval_expr(tree)) # 输出 14

进阶示例:定义可匹配类

通过 __match_args__ 控制匹配字段顺序:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Point:
__match_args__ = ("x", "y")
def __init__(self, x, y):
self.x = x
self.y = y

p = Point(3, 4)

match p:
case Point(0, 0):
print("Origin")
case Point(x, y):
print(f"Point({x}, {y})")

这会按照 __match_args__ 解构。

match/case vs if/elif

特性 match/case if/elif
简单相等判断 ✅ 可行 ✅ 可行
多模式匹配 ✅ 方便 ❌ 繁琐
解构数据结构 ✅ 直接支持 ❌ 需要手动索引
条件守卫 ✅ 支持 ✅ 支持
类型安全性 ✅ 更清晰 ❌ 依赖手动判断
性能 ⚖️ 差别不大 ⚖️ 差别不大

使用场景

适合用的情况:

  • 数据解析(JSON / dict / AST)
  • 命令路由(类似 switch)
  • 协议包解构
  • 事件处理分发
  • 状态机逻辑分支

不适合的情况:

  • 仅有简单 if 判断;
  • 需要动态逻辑的复杂条件。

注意事项

  1. case _: 必须放在最后,否则会遮蔽后续分支;
  2. 捕获变量名会自动绑定新的局部变量;
  3. 匹配是结构性的,而不是类型强制的,如 [1, 2] 匹配 tuple 也行;
  4. 对类匹配时,类需要支持 __match_args__ 或具名参数;
  5. 模式匹配不支持 case 穿透(没有“fallthrough”)。