Python基础指南之match-case模式匹配语句的使用教学
作者:星河耀银海
一、开篇:Python 3.10的里程碑特性
2021年10月,Python 3.10正式发布,其中最引人注目的新特性就是结构化模式匹配(Structural Pattern Matching)——也就是match-case语句。这不仅仅是"Python版的switch",而是一个远比switch强大得多的特性。
先看看它长什么样:
# 经典的使用场景:根据状态码返回消息
def http_status_message(code):
match code:
case 200:
return "OK"
case 404:
return "Not Found"
case 500:
return "Internal Server Error"
case _:
return "Unknown"
这看起来确实像其他语言的switch-case。但match-case的能力远超switch——它能匹配数据结构、解构对象、使用守卫条件,甚至能匹配自定义类的实例。
本文将从基础到高级,全面讲解这个Python的新利器。
版本要求
# match-case 需要 Python 3.10+
import sys
print(f"Python版本: {sys.version}")
# 检查是否支持match-case
if sys.version_info >= (3, 10):
print("✅ 支持 match-case")
else:
print("❌ 请升级到 Python 3.10 或更高版本")
二、match-case 基础语法
2.1 最简单的模式匹配
# 基本语法
# match subject:
# case pattern1:
# action1()
# case pattern2:
# action2()
# case _:
# default_action()
# 示例:星期几
def what_day(day):
match day:
case 1:
return "星期一"
case 2:
return "星期二"
case 3:
return "星期三"
case 4:
return "星期四"
case 5:
return "星期五"
case 6:
return "星期六"
case 7:
return "星期日"
case _: # _ 是通配符,匹配任何值
return "无效的日期数字"
print(what_day(1)) # 星期一
print(what_day(7)) # 星期日
print(what_day(0)) # 无效的日期数字
# 关于 _ 通配符
# _ 是一个特殊的"吸尘器"模式,匹配一切
# 不同于变量名(变量名会绑定值),_ 不会绑定
2.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 "超出范围"
for i in range(11):
print(f"{i}: {classify_number(i)}")
# 可用于合并相似的处理逻辑
def is_weekend(day):
match day.lower():
case "saturday" | "sunday":
return True
case "monday" | "tuesday" | "wednesday" | "thursday" | "friday":
return False
case _:
return None
2.3 匹配时的变量绑定
这是match-case超越switch的关键特性之一:
# match-case可以在匹配时提取值
def process_command(command):
match command.split():
case ["quit"]:
print("退出程序")
case ["hello"]:
print("你好!")
case ["add", x]: # x 绑定到第二个元素
print(f"加上 {x}")
case ["add", x, y]: # x, y 分别绑定
print(f"{x} + {y} = {int(x) + int(y)}")
case _:
print("未知命令")
process_command("quit") # 退出程序
process_command("add 10") # 加上 10
process_command("add 10 20") # 10 + 20 = 30
process_command("unknown xyz") # 未知命令
三、结构化模式匹配(核心特性)
3.1 匹配序列(列表/元组)
# 匹配不同长度和内容的序列
def analyze_sequence(seq):
match seq:
case []:
return "空序列"
case [x]:
return f"单元素序列: {x}"
case [x, y]:
return f"两元素序列: {x}, {y}"
case [x, y, z]:
return f"三元素序列: {x}, {y}, {z}"
case [first, *rest]: # *rest 收集剩余元素
return f"首元素: {first}, 剩余: {rest}"
case _:
return "不是序列"
print(analyze_sequence([])) # 空序列
print(analyze_sequence([42])) # 单元素序列: 42
print(analyze_sequence([1, 2])) # 两元素序列: 1, 2
print(analyze_sequence([1, 2, 3, 4, 5])) # 首元素: 1, 剩余: [2, 3, 4, 5]
# * 也可以出现在中间
def extract_parts(seq):
match seq:
case [first, *middle, last]:
return f"首={first}, 中={middle}, 尾={last}"
case _:
return "太短了"
print(extract_parts([1, 2, 3, 4, 5])) # 首=1, 中=[2, 3, 4], 尾=5
print(extract_parts([1, 2])) # 首=1, 中=[], 尾=2
print(extract_parts([1])) # 太短了
3.2 匹配映射(字典)
# 匹配字典结构
def analyze_config(config):
match config:
case {"host": host, "port": port}:
return f"服务器: {host}:{port}"
case {"host": host, "port": port, "debug": debug}:
return f"服务器: {host}:{port}, 调试={'开' if debug else '关'}"
case {"database": db_config}:
return f"数据库配置: {db_config}"
case {}:
return "空配置"
case _:
return "无效配置"
print(analyze_config({"host": "localhost", "port": 8080}))
# 服务器: localhost:8080
print(analyze_config({"host": "0.0.0.0", "port": 443, "debug": True}))
# 服务器: 0.0.0.0:443, 调试=开
# ⚠️ 注意匹配顺序!上面的例子有个bug:
# {"host": host, "port": port} 会先匹配,即使有debug键也会进入第一个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 {"database": db_config}:
return f"数据库配置: {db_config}"
case _:
return "无效配置"
3.3 匹配类实例
# 匹配自定义类的实例
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
class Circle:
def __init__(self, center, radius):
self.center = center
self.radius = radius
class Rectangle:
def __init__(self, top_left, bottom_right):
self.top_left = top_left
self.bottom_right = bottom_right
def describe_shape(shape):
match shape:
case Point(x=0, y=0):
return "原点"
case Point(x=x, y=y):
return f"点({x}, {y})"
case Circle(center=Point(x=x, y=y), radius=r):
return f"圆: 圆心({x}, {y}), 半径{r}"
case Rectangle(top_left=Point(x=x1, y=y1), bottom_right=Point(x=x2, y=y2)):
return f"矩形: ({x1},{y1}) 到 ({x2},{y2})"
case _:
return "未知形状"
# 使用
p1 = Point(0, 0)
p2 = Point(3, 4)
c = Circle(Point(1, 2), 5)
r = Rectangle(Point(0, 0), Point(10, 10))
print(describe_shape(p1)) # 原点
print(describe_shape(p2)) # 点(3, 4)
print(describe_shape(c)) # 圆: 圆心(1, 2), 半径5
print(describe_shape(r)) # 矩形: (0,0) 到 (10,10)
四、守卫条件(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): # n == 0
return "零"
case float(f) if f > 0:
return f"正浮点数: {f}"
case float(f) if f < 0:
return f"负浮点数: {f}"
case float(f):
return "浮点数零"
case str(s) if len(s) > 10:
return f"长字符串({len(s)}字符): {s[:10]}..."
case str(s):
return f"短字符串: {s}"
case _:
return "其他类型"
print(classify_value(42)) # 正整数: 42
print(classify_value(-3.14)) # 负浮点数: -3.14
print(classify_value("Hello")) # 短字符串: Hello
print(classify_value("Hello World! This is Python")) # 长字符串(28字符)
# 结合守卫和OR模式
def check_age(age):
match age:
case int(n) if n < 0 | n > 150:
return "无效年龄"
case int(n) if n < 18:
return "未成年人"
case int(n) if n < 65:
return "成年人"
case int(n):
return "老年人"
case _:
return "非数字输入"
五、match-case vs if-elif-else
5.1 什么时候用match-case
# ✅ 适合match-case:基于值的多分支选择
def get_day_type(day):
match day.lower():
case "monday" | "tuesday" | "wednesday" | "thursday" | "friday":
return "工作日"
case "saturday" | "sunday":
return "周末"
case _:
return "未知"
# ✅ 适合match-case:解构复杂数据结构
def process_api_response(response):
match response:
case {"status": "ok", "data": data}:
return handle_data(data)
case {"status": "error", "message": msg}:
return f"错误: {msg}"
case {"status": "error", "code": int(code)} if code >= 500:
return f"服务器错误([code])"
case {"status": "error", "code": int(code)}:
return f"客户端错误([code])"
case _:
return "未知响应格式"
# ❌ 不适合match-case:需要复杂比较逻辑
# 这种情况下if-elif-else更合适
def analyze_score(score):
# if-elif-else更合适
if score >= 90:
return "优秀"
elif score >= 80:
return "良好"
elif score >= 70:
return "中等"
else:
return "需要提升"
5.2 两者的混合使用
# match-case 和 if-elif-else 可以混合
def smart_classifier(obj):
# 先用match-case按类型分大类
match obj:
case int(n):
# 再用if-elif按范围细分
if n < 0:
return "负整数"
elif n == 0:
return "零"
elif n < 10:
return "小正整数"
else:
return "大正整数"
case str(s):
if len(s) == 0:
return "空字符串"
elif len(s) < 10:
return "短字符串"
else:
return "长字符串"
case list(items):
if len(items) == 0:
return "空列表"
elif all(isinstance(i, int) for i in items):
return "整数列表"
else:
return "混合列表"
case _:
return f"不支持的类型: {type(obj).__name__}"
六、实战案例
6.1 JSON数据验证与解析
def parse_user_data(data):
"""解析并验证用户数据"""
match data:
# 完整数据
case {
"name": str(name),
"age": int(age),
"email": str(email),
**extra # **extra 收集额外字段
} if 0 < age < 150 and "@" in email:
result = {
"name": name,
"age": age,
"email": email,
"valid": True,
}
if extra:
result["extra_fields"] = list(extra.keys())
return result
# 缺少email但有name和age
case {"name": str(name), "age": int(age)} if 0 < age < 150:
return {
"name": name,
"age": age,
"valid": True,
"warnings": ["缺少邮箱地址"],
}
# 只有name
case {"name": str(name)}:
return {
"name": name,
"valid": False,
"errors": ["缺少年龄和邮箱"],
}
# 空数据或格式不对
case dict():
return {"valid": False, "errors": ["数据格式不正确"]}
case _:
return {"valid": False, "errors": ["输入不是字典类型"]}
# 测试
test_cases = [
{"name": "张三", "age": 25, "email": "zhangsan@example.com", "city": "北京"},
{"name": "李四", "age": 30},
{"name": "王五"},
{"invalid": "data"},
"not a dict",
]
for data in test_cases:
result = parse_user_data(data)
print(f"\n输入: {data}")
print(f"输出: {result}")
6.2 简易计算器
def calculator():
"""命令行计算器,展示match-case的模式匹配能力"""
print("简易计算器(输入 'quit' 退出)")
print("支持格式:<数字> <操作符> <数字>")
print("示例:10 + 20, 3.14 * 2, 100 / 4")
while True:
user_input = input("\n> ").strip()
if not user_input:
continue
match user_input.split():
case ["quit" | "exit" | "q"]:
print("再见!")
break
case ["help" | "h" | "?"]:
print("操作符: + (加), - (减), * (乘), / (除), ** (幂), % (取模)")
print("输入 'quit' 退出, 'clear' 清零")
case ["clear" | "c"]:
print("计算器已重置")
case [left, op, right]:
try:
a, b = float(left), float(right)
match op:
case "+":
result = a + b
case "-":
result = a - b
case "*" | "×" | "x":
result = a * b
case "/" | "÷":
if b == 0:
print("❌ 除数不能为零!")
continue
result = a / b
case "**" | "^":
result = a ** b
case "%":
result = a % b
case _:
print(f"❌ 未知操作符: {op}")
continue
print(f" {a} {op} {b} = {result}")
except ValueError:
print("❌ 请输入有效的数字")
case _:
print("❌ 格式错误,请使用: <数字> <操作符> <数字>")
# 运行计算器(取消注释使用)
# calculator()
6.3 抽象语法树处理器
# 用match-case处理简单的表达式树
class Expr:
pass
class Number(Expr):
def __init__(self, value):
self.value = value
class BinOp(Expr):
def __init__(self, left, op, right):
self.left = left
self.op = op
self.right = right
class UnaryOp(Expr):
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 BinOp(left=l, op="*", right=r):
return evaluate(l) * evaluate(r)
case BinOp(left=l, op="/", right=r):
divisor = evaluate(r)
if divisor == 0:
raise ZeroDivisionError("除数不能为零")
return evaluate(l) / divisor
case UnaryOp(op="-", operand=opd):
return -evaluate(opd)
case UnaryOp(op="+", operand=opd):
return evaluate(opd)
case _:
raise ValueError(f"未知表达式: {expr}")
# 构建表达式: (-5 + 3) * 2
expr = BinOp(
BinOp(UnaryOp("-", Number(5)), "+", Number(3)),
"*",
Number(2)
)
print(f"(-5 + 3) * 2 = {evaluate(expr)}") # -4
七、本章小结
本文我们学习了Python 3.10的match-case模式匹配语句:
基本语法:match subject: case pattern: ... case _: ...,_是通配符。
OR模式:case 1 | 2 | 3: 匹配多个值。
变量绑定:case ["add", x, y]: 在匹配时提取值到变量。
结构化匹配(核心特性):
- 序列:
[first, *rest]、[first, *middle, last] - 映射:
{"key": value_pattern, **rest} - 类实例:
Point(x=x, y=y)
守卫条件:case pattern if condition: 在模式匹配基础上加条件。
选型建议:match-case适合值匹配和结构解构,if-elif-else适合范围比较。两者可以混合使用。
match-case是Python 3.10最重大的新特性。掌握了它,你处理复杂分支逻辑的能力将上升一个台阶。⌨️ 下一篇文章,我们将进入循环的世界——从while循环开始!
以上就是Python基础指南之match-case模式匹配语句的使用教学的详细内容,更多关于Python match-case语句使用的资料请关注脚本之家其它相关文章!
