2021年10月发布的Python 3.10带来了结构化模式匹配(Structural Pattern Matching),即match-case语句。它的能力远超传统switch,不仅能做值匹配,还能解构序列、映射和类实例,并支持守卫条件与变量绑定。本教程从基础语法到实战案例,系统讲解match-case的使用方法。
所有代码示例需在Python 3.10及以上版本运行,可用以下代码检查环境兼容性:
- import sys
- if sys.version_info >= (3, 10):
- print("✅ 支持 match-case")
- else:
- print("❌ 请升级到 Python 3.10 或更高版本")
复制代码
一、基础语法
1. 最简单的模式匹配
match语句后接待匹配值,每个case跟一个模式和一个冒号,形如:
- def what_day(day):
- match day:
- case 1:
- return "星期一"
- case 2:
- return "星期二"
- case 7:
- return "星期日"
- case _:
- return "无效的日期数字"
复制代码
下划线_是通配符,匹配任何未在上方明确匹配的值。注意_不会绑定值,而普通变量名会绑定。
2. OR模式匹配多个值
用竖线|分隔多个值,实现“或”逻辑:
- def classify_number(n):
- match n:
- case 0:
- return "零"
- case 1 | 2 | 3:
- return "小数字(1-3)"
- case 4 | 5 | 6:
- return "中数字(4-6)"
- case 7 | 8 | 9:
- return "大数字(7-9)"
- case _:
- return "超出范围"
复制代码
3. 变量绑定
这是match-case超越switch的关键:在匹配序列或结构时,模式中的变量会自动捕获对应的元素。
- def process_command(command):
- match command.split():
- case ["quit"]:
- print("退出程序")
- case ["add", x]:
- print(f"加上 {x}")
- case ["add", x, y]:
- print(f"{x} + {y} = {int(x) + int(y)}")
- case _:
- print("未知命令")
复制代码
二、结构化模式匹配(核心特性)
1. 匹配序列(列表/元组)
支持按长度、位置以及使用星号收集剩余元素:
- def analyze_sequence(seq):
- match seq:
- case []:
- return "空序列"
- case [x]:
- return f"单元素: {x}"
- case [x, y]:
- return f"两元素: {x}, {y}"
- case [first, *rest]:
- return f"首元素: {first}, 剩余: {rest}"
复制代码
星号也可出现在中间,例如[first, *middle, last]会分离首、尾及中间剩余元素。
2. 匹配映射(字典)
按字典键进行模式匹配,变量绑定对应值。注意case顺序影响匹配结果:更具体的模式应写在前面。
- def analyze_config_fixed(config):
- match config:
- case {"host": host, "port": port, "debug": bool(debug)}:
- return f"服务器: {host}:{port}, 调试={'开' if debug else '关'}"
- case {"host": host, "port": int(port)}:
- return f"服务器: {host}:{port}"
- case _:
- return "无效配置"
复制代码
这里利用内置类型名(如bool, int)进行类型守卫。在模式中直接写int(port)会将port与int类型匹配,同时转换类型。
3. 匹配类实例
模式中可以调用构造函数并进行属性解构:
- class Point:
- def __init__(self, x, y):
- self.x = x
- self.y = y
- def describe_shape(shape):
- match shape:
- case Point(x=0, y=0):
- return "原点"
- case Point(x=x, y=y):
- return f"点({x}, {y})"
- case _:
- return "未知形状"
复制代码
三、守卫条件(Guard)
在模式后添加if条件,做额外逻辑判断:
- def classify_value(x):
- match x:
- case int(n) if n > 0:
- return f"正整数: {n}"
- case int(n) if n < 0:
- return f"负整数: {n}"
- case int(n):
- return "零"
- case str(s) if len(s) > 10:
- return f"长字符串({len(s)}字符): {s[:10]}..."
- case str(s):
- return f"短字符串: {s}"
- case _:
- return "其他类型"
复制代码
守卫条件可结合OR模式,但注意优先级:case模式 if条件中的|需要括号(如case int(n) if n < 0 | n > 150: 实际应写作 case int(n) if n < 0 or n > 150:,注意原文的|用法有误,正确写法是条件表达式内用or)。
四、match-case vs if-elif-else
match-case适合值匹配和结构解构;if-elif-else适合范围比较、复杂逻辑。两者可混合使用,例如先用match按类型分支,再在case内部用if细分:
- def smart_classifier(obj):
- match obj:
- case int(n):
- if n < 0:
- return "负整数"
- elif n == 0:
- return "零"
- else:
- return "正整数"
- case str(s):
- if len(s) == 0:
- return "空字符串"
- else:
- return "非空字符串"
- case _:
- return "其他类型"
复制代码
五、实战案例
1. JSON数据验证与解析
利用模式匹配快速验证并提取字段:
- def parse_user_data(data):
- match data:
- case {
- "name": str(name),
- "age": int(age),
- "email": str(email),
- **extra
- } if 0 < age < 150 and "@" in email:
- return {"name": name, "age": age, "email": email, "valid": True}
- case {"name": str(name), "age": int(age)} if 0 < age < 150:
- return {"name": name, "age": age, "valid": True, "warnings": ["缺少邮箱"]}
- case dict():
- return {"valid": False, "errors": ["数据格式不正确"]}
- case _:
- return {"valid": False, "errors": ["输入不是字典"]}
复制代码
2. 简易计算器
用match-case处理命令解析和操作符分发:
- def calculator():
- print("简易计算器(输入 quit 退出)")
- while True:
- user_input = input("> ").strip()
- if not user_input:
- continue
- match user_input.split():
- case ["quit" | "exit" | "q"]:
- print("再见!")
- break
- case [left, op, right]:
- try:
- a, b = float(left), float(right)
- match op:
- case "+":
- result = a + b
- case "-":
- result = a - b
- case "*" | "×":
- result = a * b
- case "/" | "÷":
- if b == 0:
- print("除数不能为零")
- continue
- result = a / b
- case "**" | "^":
- result = a ** b
- case "%":
- result = a % b
- case _:
- print("未知操作符")
- continue
- print(f"{a} {op} {b} = {result}")
- except ValueError:
- print("请输入有效数字")
- case _:
- print("格式错误,请使用: <数字> <操作符> <数字>")
复制代码
3. 抽象语法树处理器
利用match-case递归求值表达式树:
- class Number:
- def __init__(self, value):
- self.value = value
- class BinOp:
- def __init__(self, left, op, right):
- self.left = left
- self.op = op
- self.right = right
- class UnaryOp:
- def __init__(self, op, operand):
- self.op = op
- self.operand = operand
- def evaluate(expr):
- match expr:
- case Number(value=n):
- return n
- case BinOp(left=l, op="+", right=r):
- return evaluate(l) + evaluate(r)
- case BinOp(left=l, op="*", right=r):
- return evaluate(l) * evaluate(r)
- case UnaryOp(op="-", operand=opd):
- return -evaluate(opd)
- case _:
- raise ValueError("未知表达式")
复制代码
构建表达式(-5 + 3) * 2:
- expr = BinOp(BinOp(UnaryOp("-", Number(5)), "+", Number(3)), "*", Number(2))
- print(evaluate(expr)) # -4
复制代码
总结:match-case是Python 3.10的重大特性,其结构化模式匹配能力让代码更清晰、更易维护。掌握它,你就能用更声明式的方式处理分支逻辑。建议在需要解构复杂数据结构或多值分支时优先使用,并与if-elif-else合理搭配。 |