Skip to content

Latest commit

 

History

History
157 lines (109 loc) · 4.15 KB

File metadata and controls

157 lines (109 loc) · 4.15 KB

Python 3.10 引入的 match 语句(结构化模式匹配,Structural Pattern Matching)是 Python 历史上最大的语法变化之一。

简单来说,你可以把它看作是其他语言中 switch-case超级增强版。但它不仅能匹配具体的值,还能匹配数据的结构(如列表、字典、对象),并能同时将数据拆包(解构)赋值给变量。

以下是详细的讲解和常见场景:


1. 基础语法:替代 if-elif-else

最简单的用法是匹配字面值(数字、字符串等)。这就像传统的 switch 语句。

status = 404

match status:
    case 200:
        print("请求成功")
    case 400:
        print("错误请求")
    case 404:
        print("页面未找到")
    case _:
        # 下划线 _ 表示 "其他所有情况",类似于 switch 中的 default
        print("未知状态")

2. 强大的功能:结构匹配与解构

这是 match 真正强大的地方。它可以根据数据的形状来匹配,并直接提取其中的值。

A. 匹配列表或元组 (Sequences)

假设你有一个坐标点,它可能是 (x, y) 形式的元组。

point = (0, 10)

match point:
    case (0, 0):
        print("原点")
    case (0, y):
        # 匹配 x 为 0,并将第二个元素赋值给变量 y
        print(f"在 Y 轴上,Y={y}")
    case (x, 0):
        # 匹配 y 为 0,并将第一个元素赋值给变量 x
        print(f"在 X 轴上,X={x}")
    case (x, y):
        print(f"坐标点在 ({x}, {y})")
    case _:
        print("这不是一个二维坐标")

注意:这里不需要像写正则那样麻烦,Python 会自动帮你把值“拆”出来赋给变量 xy

B. 匹配字典 (Mappings)

你可以匹配字典中是否存在特定的 Key,并提取 Value。注意:它会忽略字典中未写出的其他 Key(部分匹配)。

user = {"name": "Alice", "role": "admin", "id": 123}

match user:
    case {"role": "admin"}:
        # 只要字典里有 role: admin 这一项就匹配
        print("这是一个管理员")
    case {"role": "guest", "name": name}:
        # 匹配 role 是 guest,并把 name 的值提取出来
        print(f"访客姓名: {name}")
    case _:
        print("权限不足或未知用户")

C. 匹配类对象 (Classes)

它可以配合 dataclass 或普通类使用,直接检查对象的属性。

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

pt = Point(1, 5)

match pt:
    case Point(x=0, y=0):
        print("对象在原点")
    case Point(x=x, y=y):
        # 匹配是 Point 类型,并提取属性
        print(f"Point 对象: x={x}, y={y}")

3. 高级技巧

A. 联合匹配 (|)

使用 | 表示“或”的关系。

cmd = "stop"

match cmd:
    case "start" | "go" | "play":
        print("开始运行")
    case "stop" | "quit" | "exit":
        print("停止运行")

B. 守卫子句 (if guard)

你可以在匹配模式后加上 if 语句,进行更细致的逻辑判断。

point = (5, 5)

match point:
    case (x, y) if x == y:
        print(f"在对角线上: {x}")
    case (x, y):
        print(f"普通坐标: {x}, {y}")

C. 匹配剩余项 (*)

类似于列表解包中的 *args

command = ["move", "up", 10, 20]

match command:
    case ["quit"]:
        print("退出")
    case ["move", direction, *steps]:
        # direction 匹配 "up"
        # steps 匹配剩余列表 [10, 20]
        print(f"向 {direction} 移动,步骤: {steps}")

总结:为什么要用它?

  1. 可读性更强:处理复杂数据结构(特别是嵌套的 JSON 或配置字典)时,比一堆 if isinstance(...) and dict.get(...) 清晰得多。
  2. 解构赋值:在匹配的同时直接拿到你想要的数据,少写很多赋值代码。
  3. 安全性:强制你考虑数据结构,如果结构不匹配,代码逻辑不会乱跑。

您可以试着把手中一个复杂的 if-elif 链(特别是涉及到解析数据结构的)改写成 match 语句,看看代码是否变得更清爽了。