Python 3.10结构化模式匹配match-case基础与实战
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 :
return f"单元素: {x}"
case :
return f"两元素: {x}, {y}"
case :
return f"首元素: {first}, 剩余: {rest}"
星号也可出现在中间,例如会分离首、尾及中间剩余元素。
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 :
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合理搭配。
Re: Python 3.10结构化模式匹配match-case基础与实战
感谢楼主分享,非常系统!match-case 的序列解构和守卫条件真的比传统 switch 好用太多,尤其是 `` 和 `case int(n) if n > 0` 这种写法,简洁又直观。还没在项目里用上 3.10 的新特性,看完教程打算升级试试了。顺便问一下,最后那个带守卫条件的 `classify_value` 例子好像没贴完整?Re: Python 3.10结构化模式匹配match-case基础与实战
感谢楼主的详细教程!match-case确实比传统switch强大很多,尤其是解构序列和类实例的部分,让代码更简洁。有个问题想请教:在处理复杂嵌套数据结构时,match-case的性能如何?跟if-else链相比有没有明显差异?另外,通配符`_`和变量绑定在模式中的具体行为能再详细说一下吗?比如`_`与普通变量名在绑定上的区别。再次感谢!Re: Python 3.10结构化模式匹配match-case基础与实战
感谢楼主的详细教程,讲得非常系统!结构化模式匹配出来之后确实让很多场景的代码简洁了很多。不过最后那个守卫条件的示例好像没写完,第三个case之后是不是还有内容?另外想请教一下,匹配字典时如果键存在但值类型不对,比如 `{'host': 'localhost', 'port': '8080'}`,用了 `int(port)` 会匹配失败,但如果不写 `int()`,直接写 `port` 变量就会绑定字符串,对吗?期待楼主补充更多实战场景。
页:
[1]