Pattern matching

One of the most eye-catching features of Python 3.10 is the new match-casePattern matching. It is not just a "Python version of Switch", but a powerful tool that can deconstruct complex data, extract variables according to structure, and accurately match combinations of conditions. Originally I needed a bunch ofif-elifThe logic that can only be achieved by adding temporary variables can now be written as simple and intuitive as data description.


1. Basic entry: like Switch but more elegant

Let’s start with the most “Switch-like” usage, and you will immediately appreciate its simplicity.

1.1 Single value matching

score = 'B'

match score:
    case 'A':
        print('优秀')
    case 'B':
        print('良好')
    case 'C':
        print('及格')
    case _:          # 下划线是“通配符”,匹配所有没有命中前面的情况
        print('无效成绩')

Matching is performed sequentially from top to bottom, and the first one that matches successfullycaseThe branch will be executed, and subsequent ones will not be checked again._It must be placed last, otherwise subsequent branches will never be triggered.

1.2 Comparison of traditional writing methods

The same logic if usedif-elif-else, you need to write the same variable repeatedly:

score = 'B'

if score == 'A':
    print('优秀')
elif score == 'B':
    print('良好')
elif score == 'C':
    print('及格')
else:
    print('无效成绩')

match-caseThe advantage is clear goals and clear structure - you can see at a glance that all branches deal withscore, there will be no "a certainelifThe embarrassment of accidentally writing the wrong variable".


2. Advanced usage: Patterns are much more than constants

match-caseThe real power of "patterns" is that they can be nested, variables can be bound, and conditions can be added.

2.1 Multi-value combinations and guard conditions

use|Several constants can be combined into a pattern usingifAdd "guard" for further filtering:

age = 15

match age:
    case x if x < 10:                 # 绑定变量 x,再用 if 过滤
        print(f'10 岁以下: {x}')
    case 10:
        print('正好 10 岁')
    case 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18:   # 多个值合并
        print('11-18 岁')
    case 19:
        print('19 岁')
    case _:
        print('其他年龄')

Tips:case x if x < 10inxMatching values ​​will be captured, followed by guard conditionsif x < 10Then decide whether you really want to take this branch. This writing method is particularly suitable for the scenario of "match first and then verify the conditions".

2.2 Sequence deconstruction: lists and tuples in one move

When processing fixed-structure data such as command line parameters and coordinate lists, you can directly write the "structure" into the pattern:

args = ['gcc', 'hello.c', 'world.c', '-o', 'hello']

match args:
    case ['gcc']:
        print('错误:缺少编译源文件')
    case ['gcc', file1, *files]:      # *files 匹配剩余任意多个元素
        print(f'主源文件: {file1}, 其他源文件: {", ".join(files)}')
    case ['clean']:
        print('清理所有编译产物')
    case _:
        print('无效编译命令,请检查参数')

here*filesJust like in function parameter unpacking*args, can collect all remaining elements in the list into a list.


3. advanced-features: dismantle complex objects

3.1 Match custom classes/data classes

Cooperatedataclass, you can directly match the object's attribute value pattern and automatically extract the required attributes into variables:

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

point = Point(0, 5)

match point:
    case Point(x=0, y=0):
        print("原点 (0,0)")
    case Point(x=0, y=y_val):       # 只固定 x=0,y 的值捕获到 y_val
        print(f"Y 轴上的点,Y 坐标: {y_val}")
    case Point(x=x_val, y=0):
        print(f"X 轴上的点,X 坐标: {x_val}")
    case Point(x, y):               # 捕获所有属性,名字与属性名相同
        print(f"平面普通点: ({x}, {y})")
    case _:
        print("不是有效的 Point 实例")

This way, we don't need to unpack the object first and then write a bunch ofif, the code reads like "if the point is at the origin, then so and so".

3.2 Partial matching of dictionary

Dictionary mode is equally powerful: you only need to match the keys you care about, and other keys will be ignored; if you want to retain unmatched key-value pairs, you can use**restcollect:

config = {'type': 'video', 'format': 'mp4', 'duration': 120, 'resolution': '1080p'}

match config:
    case {'type': 'video', 'format': 'mp4', **rest}:
        print(f"MP4 视频文件,附加信息: {rest}")
    case {'type': 'audio', 'format': 'mp3'}:
        print("MP3 音频文件")
    case {'type': _, 'duration': t} if t > 60:    # 通配 type,只提取 duration
        print(f"长内容(时长 > 60 秒): {t} 秒")
    case _:
        print("未知配置格式")

Notice:{'type': _}in_means "match any value, but do not bind variables", and the same as in the previous list_It's the same reason.


4. Pitfall avoidance guide and best practices

  1. Matching order determines everything Pattern matching is performed strictly in the order in which the code is written. Once a hit is made, no further attempts will be made. So be sure to put the most specific and constrained mode first.

    # 正确:具体模式在前
    match point:
        case Point(x=0, y=0): ...
        case Point(x=0): ...
    # 错误:Point(x=0) 会连原点一起吞掉,导致 Point(x=0, y=0) 永不被触发
  2. ** wildcard_Can only be placed at the end** if you putcase _:If it is written in the middle, all branches behind it will become "dead code", and there will be problems with the program logic.

  3. A beautiful way of writing type matching You can directly use the built-in type name as the pattern and bind the converted variable at the same time:

    match input_value:
        case int(i):
            print(f"整数,值: {i}")
        case str(s) if len(s) > 0:
            print(f"非空字符串,值: {s}")
        case _:
            print("既不是有效整数,也不是非空字符串")

This is better thanisinstance()Adding temporary variables is much more refreshing.

  1. Simple branches do not need to be used deliberately If there are only 2 to 3 single value judgments, directly useif-elseMight be easier.match-caseThe advantage lies in complex structure matching rather than replacing allifstatement.

5. Two practical examples

5.1 HTTP status code processing

In back-end development or crawlers, it is often necessary to do different processing according to the status code. Usematch-caseYou can make the code clear at a glance:

status_code = 403

match status_code:
    case 200:
        print("✅ 请求成功")
    case 301 | 302 | 303 | 307:
        print("🔄 资源重定向")
    case 400:
        print("❌ 客户端请求参数错误")
    case 401 | 403:
        print("🔒 权限认证问题")
    case 404:
        print("📭 资源未找到")
    case 500 | 502 | 503:
        print("💥 服务器端错误")
    case code:                          # 捕获未知状态码到变量 code
        print(f"❓ 未知状态码: {code}")

The last branch is useless_Instead, it was usedcase code:, the effect is the same, and you can also access the specific value - this is a more friendly implementation.

5.2 Lightweight command line parser

Here is a simple interactive command loop that uses pattern matching for command parsing:

while True:
    user_input = input(">>> 请输入命令(输入 exit 退出): ").strip().split()
    if not user_input:
        continue

    match user_input:
        case ['exit']:
            print("👋 退出程序")
            break
        case ['help']:
            print("📚 支持的命令:exit、help、run <文件名>、search <关键词>...")
        case ['run', filename]:
            print(f"▶️ 正在运行文件: {filename}")
        case ['search', *keywords]:
            print(f"🔍 正在搜索关键词: {' '.join(keywords)}")
        case ['delete', filename] if filename.endswith('.txt'):
            print(f"⚠️ 确认删除 TXT 文件: {filename}?")
        case _:
            print("❌ 无效命令,请输入 help 查看帮助")

List mode coordination*and guard conditions, making command parsing safe and flexible, and especially convenient when adding new commands.


Summarize

Pythonmatch-caseFar from a simple Switch clone, it's a modern, expressive structured matchmaking system:

  • ✅ Replace duplicatesif-elif-elsechain to make branch intentions clearer
  • ✅ Directly disassemble lists, tuples, dictionaries, and custom objects
  • ✅ Combine guard conditions and variable binding to complete complex condition extraction
  • ✅ Greatly improve code readability and maintainability

If you are using Python 3.10 and above, when encountering multi-branch + data extraction scenarios, please give priority tomatch-case, it will make your code concise and professional.