Python match 语句:从"开关面板"到"智能路由器"的模式匹配艺术
引言:为什么需要 match?
想象你是一个餐厅的收银员,需要处理各种支付方式:
- 现金 → 直接收款
- 微信 → 扫码
- 支付宝 → 扫码
- 信用卡 → 刷卡
- 其他 → 询问顾客
如果用 if-elif-else,代码会像瀑布一样长:
payment = '微信'
if payment == '现金':
print('请收钱')
elif payment == '微信':
print('请打开微信收款码')
elif payment == '支付宝':
print('请打开支付宝收款码')
elif payment == '信用卡':
print('请刷卡')
else:
print('请问您怎么支付?')而 Python 3.10+ 引入的 match 语句,让这种多分支选择变得像开关面板一样清晰:
match payment:
case '现金':
print('请收钱')
case '微信':
print('请打开微信收款码')
case '支付宝':
print('请打开支付宝收款码')
case '信用卡':
print('请刷卡')
case _:
print('请问您怎么支付?')match 语句让代码更像自然语言,一眼就能看出"针对不同情况做什么"。
一、match 基础:像开关一样清晰
1.1 最简单的 match
score = 'B'
match score:
case 'A':
print('score is A.')
case 'B':
print('score is B.')
case 'C':
print('score is C.')
case _: # _ 表示"其他所有情况"
print('invalid score.')生活化理解:match 就像配电箱里的开关面板——每个开关(case)对应一种情况,电流(程序执行)找到匹配的开关就停下。
1.2 语法规则
match 变量:
case 值1:
# 匹配值1时执行
case 值2:
# 匹配值2时执行
case _:
# 其他所有情况(可选)关键规则:
match后面跟要匹配的变量case后面跟具体的值case _是"兜底"情况,只能放在最后- 每个
case执行完后自动跳出,不需要break
1.3 match vs if-elif:何时用哪个?
| 场景 | 推荐写法 | 原因 |
|---|---|---|
| 2-3 个简单条件 | if-elif-else | 简单直观 |
| 4 个以上分支 | match | 更清晰易读 |
| 需要范围判断 | if-elif-else | match 不擅长范围 |
| 需要匹配多个值 | match | 支持 | 语法 |
| 需要解构复杂数据 | match | 支持列表、字典等解构 |
结论:match 是 if-elif 的补充,不是替代。简单判断用 if,复杂多分支用 match。
二、复杂匹配:超越简单的值比较
2.1 匹配多个值:| 语法
age = 15
match age:
case 10:
print('10 years old.')
case 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18:
print('11~18 years old.')
case 19:
print('19 years old.')
case _:
print('not sure.')生活化理解:就像电影院售票——"12岁以下儿童票"和"65岁以上老人票"是同一个价格。| 就是"或者"的意思。
2.2 带条件的匹配:if 守卫
age = 15
match age:
case x if x < 10:
print(f'< 10 years old: {x}')
case x if x < 20:
print(f'10~19 years old: {x}')
case _:
print('20+ years old.')注意:case x if x < 10 中的 x 是绑定变量,会把匹配的值赋给 x。
生活化理解:就像机场安检——"如果行李小于20寸,走快速通道;如果小于32寸,走普通通道"。
2.3 绑定变量:把值"抓"出来
point = (3, 5)
match point:
case (0, 0):
print('原点')
case (x, 0):
print(f'在X轴上,x={x}')
case (0, y):
print(f'在Y轴上,y={y}')
case (x, y):
print(f'坐标:x={x}, y={y}')输出:坐标:x=3, y=5
生活化理解:就像拆快递——case (x, y) 把包裹里的两个东西分别拿出来,贴上标签 x 和 y。
三、匹配列表:解构复杂数据
3.1 匹配固定长度的列表
args = ['gcc', 'hello.c']
match args:
case ['gcc']:
print('gcc: missing source file(s).')
case ['gcc', file1]:
print(f'gcc compile: {file1}')
case ['clean']:
print('clean')
case _:
print('invalid command.')执行逻辑:
case ['gcc']:列表只有 1 个元素,且是'gcc'case ['gcc', file1]:列表有 2 个元素,第一个是'gcc',第二个绑定到file1case ['clean']:列表只有 1 个元素,且是'clean'
3.2 匹配可变长度的列表:* 语法
args = ['gcc', 'hello.c', 'world.c', 'main.c']
match args:
case ['gcc']:
print('gcc: missing source file(s).')
case ['gcc', file1, *files]:
print(f'gcc compile: {file1}, and {len(files)} more files: {files}')
case ['clean']:
print('clean')
case _:
print('invalid command.')输出:gcc compile: hello.c, and 2 more files: ['world.c', 'main.c']
生活化理解:file1 是"第一个文件",*files 是"剩下的所有文件"。就像点名——"张三到!还有李四、王五、赵六都到了"。
3.3 匹配嵌套列表
data = ['user', '张三', ['北京', '上海']]
match data:
case ['user', name, [city1, city2]]:
print(f'用户 {name} 常驻 {city1} 和 {city2}')
case _:
print('未知格式')输出:用户 张三 常驻 北京 和 上海
四、match 的高级用法
4.1 匹配字典
user = {'name': '张三', 'age': 25, 'city': '北京'}
match user:
case {'name': name, 'age': age}:
print(f'{name} 今年 {age} 岁')
case {'name': name}:
print(f'用户:{name}')
case _:
print('未知用户')输出:张三 今年 25 岁
注意:字典匹配是"部分匹配"——只要包含指定的 key 就匹配,不关心其他 key。
4.2 匹配对象
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(3, 5)
match p:
case Point(x=0, y=0):
print('原点')
case Point(x=x, y=0):
print(f'X轴上的点,x={x}')
case Point(x=0, y=y):
print(f'Y轴上的点,y={y}')
case Point(x=x, y=y):
print(f'坐标:x={x}, y={y}')输出:坐标:x=3, y=5
4.3 组合使用:匹配 + 条件 + 解构
command = ['move', 'north', 10]
match command:
case ['move', direction, steps] if steps > 0:
print(f'向 {direction} 移动 {steps} 步')
case ['move', direction, steps] if steps == 0:
print('原地不动')
case ['move', direction, steps]:
print('步数不能为负')
case _:
print('未知命令')五、常见误区与陷阱
5.1 误区一:case _ 不在最后
# ❌ 错误:_ 会拦截所有情况,后面的 case 永远不会执行
match score:
case _:
print('其他')
case 'A':
print('A')
# ✅ 正确:_ 放在最后
match score:
case 'A':
print('A')
case _:
print('其他')5.2 误区二:把变量名当值匹配
# ❌ 错误:case x 中的 x 是变量绑定,不是匹配值 x
status = 'x'
match status:
case x: # 这会匹配任何值,并把值赋给 x!
print('匹配了')
case _:
print('没匹配')
# ✅ 正确:匹配具体值用引号
match status:
case 'x': # 只匹配字符串 'x'
print('匹配了 x')
case _:
print('没匹配')5.3 误区三:列表匹配时长度不符
args = ['gcc', 'hello.c']
match args:
case ['gcc']: # 不匹配:长度是 2,不是 1
print('缺文件')
case ['gcc', file1]: # 匹配!
print(f'编译 {file1}')
case _:
print('其他')5.4 误区四:match 的版本问题
# ❌ Python 3.9 及以下不支持 match
# 会报错:SyntaxError: invalid syntax
# ✅ 检查 Python 版本
import sys
print(sys.version) # 需要 3.10+六、实战案例
案例 1:命令行参数解析器
def parse_command(args):
match args:
case ['help']:
print('可用命令:gcc, clean, version')
case ['version']:
print('v1.0.0')
case ['gcc']:
print('错误:缺少源文件')
case ['gcc', file1]:
print(f'编译:{file1}')
case ['gcc', file1, *files]:
print(f'编译:{file1},以及 {files}')
case ['clean']:
print('清理临时文件')
case _:
print('未知命令,输入 help 查看帮助')
# 测试
parse_command(['gcc', 'main.c', 'utils.c'])
# 输出:编译:main.c,以及 ['utils.c']案例 2:HTTP 状态码处理
def handle_response(status):
match status:
case 200:
return '成功'
case 301 | 302:
return '重定向'
case 400:
return '请求错误'
case 401:
return '未授权'
case 403:
return '禁止访问'
case 404:
return '未找到'
case 500:
return '服务器错误'
case _:
return f'未知状态码:{status}'
print(handle_response(404)) # 未找到
print(handle_response(999)) # 未知状态码:999案例 3:坐标点分类
def classify_point(point):
match point:
case (0, 0):
return '原点'
case (x, 0) if x > 0:
return 'X轴正半轴'
case (x, 0) if x < 0:
return 'X轴负半轴'
case (0, y) if y > 0:
return 'Y轴正半轴'
case (0, y) if y < 0:
return 'Y轴负半轴'
case (x, y) if x > 0 and y > 0:
return '第一象限'
case (x, y) if x < 0 and y > 0:
return '第二象限'
case (x, y) if x < 0 and y < 0:
return '第三象限'
case (x, y) if x > 0 and y < 0:
return '第四象限'
case _:
return '未知'
print(classify_point((3, 5))) # 第一象限
print(classify_point((0, 0))) # 原点案例 4:简易计算器
def calculate(expression):
match expression:
case [x, '+', y]:
return x + y
case [x, '-', y]:
return x - y
case [x, '*', y]:
return x * y
case [x, '/', y] if y != 0:
return x / y
case [x, '/', 0]:
return '错误:除数不能为0'
case _:
return '不支持的表达式'
print(calculate([10, '+', 5])) # 15
print(calculate([10, '/', 0])) # 错误:除数不能为0七、动手练习
练习 1:用 match 重写下面的 if-elif 代码
day = 'Monday'
if day == 'Monday':
print('星期一')
elif day == 'Tuesday':
print('星期二')
elif day == 'Wednesday':
print('星期三')
elif day == 'Thursday':
print('星期四')
elif day == 'Friday':
print('星期五')
elif day == 'Saturday' or day == 'Sunday':
print('周末')
else:
print('无效输入')参考答案:
day = 'Monday'
match day:
case 'Monday':
print('星期一')
case 'Tuesday':
print('星期二')
case 'Wednesday':
print('星期三')
case 'Thursday':
print('星期四')
case 'Friday':
print('星期五')
case 'Saturday' | 'Sunday':
print('周末')
case _:
print('无效输入')练习 2:解释下面代码的输出
args = ['run', 'fast', 'now']
match args:
case ['run']:
print('run')
case ['run', speed]:
print(f'run {speed}')
case ['run', speed, time]:
print(f'run {speed} at {time}')
case _:
print('unknown')答案:run fast at now——第三个 case 匹配成功,speed='fast',time='now'。
总结
| 概念 | 核心要点 |
|---|---|
| match 语句 | Python 3.10+ 的多分支匹配语法 |
| case 值 | 匹配具体的值 |
case _ | 兜底情况,只能放最后 |
case a | b | 匹配多个值中的任意一个 |
case x if 条件 | 带条件的匹配 |
| 绑定变量 | case [x, y] 把值赋给 x 和 y |
*变量 | 匹配剩余的所有元素 |
| 适用场景 | 多分支选择、命令解析、数据解构 |
记住:match 是你的智能开关面板——简单值用 case 值,多值用 |,条件用 if,解构用绑定变量,兜底用 _。
本文基于廖雪峰 Python 教程重新撰写,补充了大量背景知识、生活化类比和实战场景。推荐继续阅读:循环