Skip to content

Python match 语句:从"开关面板"到"智能路由器"的模式匹配艺术

引言:为什么需要 match?

想象你是一个餐厅的收银员,需要处理各种支付方式:

  • 现金 → 直接收款
  • 微信 → 扫码
  • 支付宝 → 扫码
  • 信用卡 → 刷卡
  • 其他 → 询问顾客

如果用 if-elif-else,代码会像瀑布一样长:

python
payment = '微信'

if payment == '现金':
    print('请收钱')
elif payment == '微信':
    print('请打开微信收款码')
elif payment == '支付宝':
    print('请打开支付宝收款码')
elif payment == '信用卡':
    print('请刷卡')
else:
    print('请问您怎么支付?')

而 Python 3.10+ 引入的 match 语句,让这种多分支选择变得像开关面板一样清晰:

python
match payment:
    case '现金':
        print('请收钱')
    case '微信':
        print('请打开微信收款码')
    case '支付宝':
        print('请打开支付宝收款码')
    case '信用卡':
        print('请刷卡')
    case _:
        print('请问您怎么支付?')

match 语句让代码更像自然语言,一眼就能看出"针对不同情况做什么"。


一、match 基础:像开关一样清晰

1.1 最简单的 match

python
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 语法规则

python
match 变量:
    case 值1:
        # 匹配值1时执行
    case 值2:
        # 匹配值2时执行
    case _:
        # 其他所有情况(可选)

关键规则

  1. match 后面跟要匹配的变量
  2. case 后面跟具体的值
  3. case _ 是"兜底"情况,只能放在最后
  4. 每个 case 执行完后自动跳出,不需要 break

1.3 match vs if-elif:何时用哪个?

场景推荐写法原因
2-3 个简单条件if-elif-else简单直观
4 个以上分支match更清晰易读
需要范围判断if-elif-elsematch 不擅长范围
需要匹配多个值match支持 | 语法
需要解构复杂数据match支持列表、字典等解构

结论matchif-elif 的补充,不是替代。简单判断用 if,复杂多分支用 match


二、复杂匹配:超越简单的值比较

2.1 匹配多个值:| 语法

python
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 守卫

python
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 绑定变量:把值"抓"出来

python
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) 把包裹里的两个东西分别拿出来,贴上标签 xy


三、匹配列表:解构复杂数据

3.1 匹配固定长度的列表

python
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.')

执行逻辑

  1. case ['gcc']:列表只有 1 个元素,且是 'gcc'
  2. case ['gcc', file1]:列表有 2 个元素,第一个是 'gcc',第二个绑定到 file1
  3. case ['clean']:列表只有 1 个元素,且是 'clean'

3.2 匹配可变长度的列表:* 语法

python
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 匹配嵌套列表

python
data = ['user', '张三', ['北京', '上海']]

match data:
    case ['user', name, [city1, city2]]:
        print(f'用户 {name} 常驻 {city1}{city2}')
    case _:
        print('未知格式')

输出用户 张三 常驻 北京 和 上海


四、match 的高级用法

4.1 匹配字典

python
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 匹配对象

python
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 组合使用:匹配 + 条件 + 解构

python
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 _ 不在最后

python
# ❌ 错误:_ 会拦截所有情况,后面的 case 永远不会执行
match score:
    case _:
        print('其他')
    case 'A':
        print('A')

# ✅ 正确:_ 放在最后
match score:
    case 'A':
        print('A')
    case _:
        print('其他')

5.2 误区二:把变量名当值匹配

python
# ❌ 错误: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 误区三:列表匹配时长度不符

python
args = ['gcc', 'hello.c']

match args:
    case ['gcc']:              # 不匹配:长度是 2,不是 1
        print('缺文件')
    case ['gcc', file1]:       # 匹配!
        print(f'编译 {file1}')
    case _:
        print('其他')

5.4 误区四:match 的版本问题

python
# ❌ Python 3.9 及以下不支持 match
# 会报错:SyntaxError: invalid syntax

# ✅ 检查 Python 版本
import sys
print(sys.version)    # 需要 3.10+

六、实战案例

案例 1:命令行参数解析器

python
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 状态码处理

python
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:坐标点分类

python
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:简易计算器

python
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 代码

python
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('无效输入')

参考答案

python
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:解释下面代码的输出

python
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 教程重新撰写,补充了大量背景知识、生活化类比和实战场景。推荐继续阅读:循环