李成笔记网

专注域名、站长SEO知识分享与实战技巧

Python的`match`表达式(python match group)

我们来详细讲解一下Python的`match`表达式,它是在 **Python 3.10** 版本中正式引入的一个新特性,被称为“结构化模式匹配”(Structural Pattern Matching)。


在Python 3.10之前,如果需要根据变量的值或结构执行不同的操作,通常依赖一长串的`if/elif/else`语句。`match`语句提供了一种更具声明性、可读性更高且功能更强大的方式来处理这类逻辑,尤其是在处理复杂的数据结构时。


### 核心概念


Python的`match`语句与MoonBit或Rust中的`match`非常相似,但也有其自身的特点。其核心思想是:


1. **结构匹配**:它不仅仅是检查值的相等性,更重要的是检查被匹配对象的**结构**。例如,你可以检查一个列表是否包含特定数量的元素,或者一个字典是否包含特定的键。

2. **解构与绑定**:在匹配成功的同时,可以将对象中的部分或全部数据提取出来,并赋值给新的变量。

3. **可读性**:对于复杂的条件分支,`match`语句通常比`if/elif/else`链条更清晰、更易于理解。


### 基本语法


```python

match subject:

case <pattern_1>:

# 当 subject 匹配 pattern_1 时执行的代码

case <pattern_2>:

# 当 subject 匹配 pattern_2 时执行的代码

case _: # 通配符,可选

# 当以上所有 case 都不匹配时执行的代码

```


- `subject`:你想要进行匹配的变量或值。

- `case <pattern>`:一个`case`块包含一个模式。Python会自上而下地逐一尝试匹配`subject`与每个`case`的模式。

- **一旦找到第一个成功匹配的`case`,就会执行其对应的代码块,然后`match`语句立即结束**。这一点与C语言的`switch`不同,不需要`break`。

- `_` (下划线):作为通配符(Wildcard Pattern),可以匹配任何东西,通常放在最后一个`case`,用于处理所有其他未匹配的情况。如果所有`case`都不匹配且没有通配符`case`,则`match`语句不执行任何操作。


---


### `match` 的常用模式详解


#### 1. 字面量模式 (Literal Pattern)


这是最基础的模式,用于匹配精确的值,如数字、字符串、`True`、`False`和`None`。


```python

def http_status(status):

match status:

case 200:

return "OK"

case 404:

return "Not Found"

case 500:

return "Internal Server Error"

case _:

return "Unknown Status"


print(http_status(404)) # 输出: Not Found

```


#### 2. 捕获模式 (Capture Pattern)


如果一个模式是一个未被`_`占用的变量名,它就会匹配成功,并将`subject`的值**捕获**(或绑定)到这个变量上。


```python

command = "send user@example.com"


match command.split():

case ["send", email]: # 捕获第二个元素到变量 email

print(f"Sending email to: {email}")

case ["quit"]:

print("Quitting...")

case _:

print("Unknown command")


# 输出: Sending email to: user@example.com

```


#### 3. 通配符模式 (Wildcard Pattern)


如前所述,`_`可以匹配任何值,但**不会**将值绑定到任何变量。它用于表示“我们不关心这个位置的值”。


#### 4. OR 模式 (`|`)


可以在一个`case`中使用`|`来组合多个字面量模式,表示“或”的关系。


```python

def process_code(code):

match code:

case 200 | 201 | 202:

return "Success"

case 400 | 401 | 403 | 404:

return "Client Error"

case _:

return "Other"


print(process_code(403)) # 输出: Client Error

```


#### 5. 序列模式 (Sequence Pattern)


用于匹配序列类型的数据,如列表(list)和元组(tuple)。它非常强大,可以检查序列的长度和内容。


```python

data = [1, "hello", 3.14]


match data:

# 精确匹配

case [1, "hello", 3.14]:

print("Exact match")

# 使用捕获模式

case [x, y, z]:

print(f"Matched three items: {x}, {y}, {z}")

# 结合字面量和捕获模式

case [1, "hello", z]:

print(f"The third item is {z}")


# 使用 * 来匹配序列中的零个或多个项 (类似JS的...rest)

case [first, *rest]:

print(f"First item: {first}, rest: {rest}") # rest 会是一个列表


# 也可以放在中间或结尾

case [first, *middle, last]:

print(f"First: {first}, Middle: {middle}, Last: {last}")

```

如果`data`是`[1, "hello", 3.14, "world"]`,最后一个`case`会输出:

`First: 1, Middle: ['hello', 3.14], Last: 'world'`


#### 6. 映射模式 (Mapping Pattern)


用于匹配字典(dict)等映射类型的数据。可以检查特定键是否存在,并捕获对应的值。


```python

action = {"command": "draw", "shape": "circle", "x": 10, "y": 20}


match action:

# 匹配包含特定键的字典,并捕获值

case {"command": "draw", "shape": s}:

print(f"Drawing a {s}")


# 捕获所有剩余的键值对到 a **rest** 变量中

case {"command": "move", **rest}:

print(f"Moving with parameters: {rest}")


# 只检查键是否存在,不关心值

case {"error": _}:

print("An error occurred")

```

如果`action`是`{"command": "move", "dx": 5, "dy": -5}`,第二个`case`会输出:

`Moving with parameters: {'dx': 5, 'dy': -5}`


#### 7. 类模式 (Class Pattern)


可以根据对象的类(类型)以及其属性来进行匹配。


```python

from dataclasses import dataclass


@dataclass

class Point:

x: int

y: int


def locate(p):

match p:

# 匹配一个 Point 实例,并捕获其属性

case Point(x=0, y=0):

print("At the origin")

case Point(x=x, y=0):

print(f"On the x-axis at {x}")

case Point(x=0, y=y):

print(f"On the y-axis at {y}")

case Point(x=x, y=y):

print(f"At ({x}, {y})")

case _:

print("Not a point")


locate(Point(3, 0)) # 输出: On the x-axis at 3

```


#### 8. 守卫 (Guards)


在`case`模式的末尾,可以添加一个`if`子句,称为“守卫”。只有当模式匹配成功 **并且** `if`条件为`True`时,这个`case`才算最终匹配成功。


```python

def process_point(p):

match p:

# 守卫条件可以使用模式中捕获的变量

case Point(x=x, y=y) if x == y:

print(f"On the y=x line at ({x}, {y})")

case Point(x=x, y=y):

print(f"Just a regular point at ({x}, {y})")


process_point(Point(5, 5)) # 输出: On the y=x line at (5, 5)

process_point(Point(5, 6)) # 输出: Just a regular point at (5, 6)

```


### 总结


Python的`match`语句是一个功能非常丰富的工具,它极大地增强了Python处理复杂数据结构和条件逻辑的能力。


- **优点**:代码更具可读性、更安全(虽然不像MoonBit那样有编译时穷尽性检查)、表达力强。

- **适用场景**:解析器、状态机、处理API响应、树形数据遍历、根据数据结构执行不同操作等。

- **与`if/elif`的区别**:`if/elif`主要基于布尔表达式求值,而`match`主要基于**结构**匹配和解构。对于简单的值判断,`if/elif`可能更直接;但对于需要检查数据结构并提取其中内容的情况,`match`无疑是更优的选择。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言