Python 模式匹配
最后修改于 2024 年 1 月 29 日
在本文中,我们将展示如何在 Python 中使用模式匹配。
模式匹配使用 match/case 关键字完成。它在 Python 3.10 中引入,名称为结构化模式匹配。
模式匹配是一种强大的控制流构造,它允许我们将一个值与一系列模式进行比较,然后根据匹配的模式执行代码。它比 if/else 语句或传统的 switch 语句更高级。
在 if/else 或 switch 语句中,每个单独的条件称为一个分支;在模式匹配中,则使用臂(arm)一词。
Python 模式匹配字面量
在第一个示例中,我们匹配简单的字面量值。
#!/usr/bin/python
langs = ['russian', 'slovak', 'german',
'swedish', 'hungarian', 'french', 'spanish']
print('say hello')
for lang in langs:
match lang:
case 'russian':
print('привет')
case 'hungarian':
print('szia')
case 'french':
print('salut')
case 'spanish':
print('hola')
case 'slovak':
print('ahoj')
case 'german':
print('hallo')
case 'swedish':
print('Hallå')
我们有一个语言列表。我们遍历列表,为每种语言说“你好”。
for lang in langs:
match lang:
match 关键字后面跟着要匹配的选项,然后是一个冒号。
case 'russian':
print('привет')
每个臂都以 case、一个选项和一个冒号开头。
$ ./first.py say hello привет ahoj hallo Hallå szia salut hola
Python 模式匹配多选项
我们可以用 | 为单行提供多个选项。
#!/usr/bin/python
grades = ['A', 'B', 'C', 'D', 'E', 'F', 'FX']
for grade in grades:
match grade:
case 'A' | 'B' | 'C' | 'D' | 'E' | 'F':
print('passed')
case 'FX':
print('failed')
我们有一个成绩列表。对于 A 到 F 的成绩,我们通过了示例。对于 FX 成绩,我们考试不及格。
$ ./grades.py passed passed passed passed passed passed failed
Python 模式匹配通配符
我们可以使用通配符 _ 来表示不匹配任何特定模式的值,或者它也可以用于所有其他模式。
#!/usr/bin/python
def factorial(n):
match n:
case 0 | 1:
return 1
case _:
return n * factorial(n - 1)
for i in range(17):
print(i, factorial(i))
我们使用 match/case 创建了一个阶乘函数。
match n:
case 0 | 1:
return 1
case _:
return n * factorial(n - 1)
对于值 0 和 1,我们返回 1。对于所有其他值,我们递归调用阶乘函数。
$ ./factorial.py 0 1 1 1 2 2 3 6 4 24 5 120 6 720 7 5040 8 40320 9 362880 10 3628800 11 39916800 12 479001600 13 6227020800 14 87178291200 15 1307674368000 16 20922789888000
Python 模式匹配守卫
if 条件形式的守卫可以在臂上执行。
#!/usr/bin/python
import random
n = random.randint(-5, 5)
match n:
case n if n < 0:
print(f"{n}: negative value")
case n if n == 0:
print(f"{n}: zero")
case n if n > 0:
print(f"{n}: positive value")
该示例选择一个随机整数。使用 match/case,我们确定该值是负数、零还是正数。
case n if n < 0:
print(f"{n}: negative value")
如果 n 小于零,则执行此臂。
Python 模式匹配对象
我们可以对 Python 对象进行模式匹配。
from dataclasses import dataclass
@dataclass
class Cat:
name: str
@dataclass
class Dog:
name: str
@dataclass
class Person:
name: str
data = [Cat('Missy'), Dog('Jasper'), Dog('Ace'), Person('Peter'), 'Jupiter']
for e in data:
match e:
case Cat(name) | Dog(name):
print(f'{name} is a pet')
case Person(name):
print(f'{name} is a human')
case _:
print(f'unknown')
我们有三个类:Cat、Dog 和 Person。使用 match/case,我们检查我们拥有的是哪种类的对象。
case Cat(name) | Dog(name):
print(f'{name} is a pet')
此臂检查猫或狗。
case Person(name):
print(f'{name} is a human')
此臂检查 Person 对象。
case _:
print(f'unknown')
对于我们无法识别的对象,我们使用通配符。
$ ./objects.py Missy is a pet Jasper is a pet Ace is a pet Peter is a human unknown
在下一个示例中,我们处理 Point 对象。
#!/usr/bin/python
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
def check(p):
match p:
case Point(x=0, y=0):
print("Origin")
case Point(x, y) if y == 0:
print(f"on x axis")
case Point(x, y) if x == 0:
print(f"on y axis")
case Point(x, y) if x > 0 and y > 0:
print("Q I")
case Point(x, y) if x < 0 and y > 0:
print("Q II")
case Point(x, y) if x < 0 and y < 0:
print("Q III")
case Point(x, y) if x > 0 and y < 0:
print("Q IV")
case _:
print("Not a point")
points = [Point(3, 0), Point(0, 0), Point(-4, -5), Point(-4, 0), Point(0, 5),
Point(4, 8), Point(-5, 3), Point(6, -4)]
for p in points:
check(p)
根据坐标,我们将点对象分配给原点、x 轴和 y 轴,或四个象限之一。
$ ./points.py on x axis Origin Q III on x axis on y axis Q I Q II Q IV
Python 模式匹配枚举
模式匹配可以有效地与枚举一起使用。
#!/usr/bin/python
from enum import Enum
import random
Day = Enum('Day', 'Monday Tuesday Wednesday Thursday Friday Saturday Sunday')
days = [Day.Monday, Day.Tuesday, Day.Wednesday,
Day.Thursday, Day.Friday, Day.Saturday, Day.Sunday]
res = random.sample(days, 4)
for e in res:
match e:
case Day.Monday:
print("monday")
case Day.Tuesday:
print("tuesday")
case Day.Wednesday:
print("wednesay")
case Day.Thursday:
print("thursday")
case Day.Friday:
print("friday")
case Day.Saturday:
print("saturday")
case Day.Sunday:
print("sunday")
在示例中,我们定义了一个 Day 枚举。
days = [Day.Monday, Day.Tuesday, Day.Wednesday,
Day.Thursday, Day.Friday, Day.Saturday, Day.Sunday]
res = random.sample(days, 4)
我们从列表中随机选择四天。
for e in res:
match e:
case Day.Monday:
print("monday")
case Day.Tuesday:
print("tuesday")
case Day.Wednesday:
print("wednesay")
case Day.Thursday:
print("thursday")
case Day.Friday:
print("friday")
case Day.Saturday:
print("saturday")
case Day.Sunday:
print("sunday")
我们检查四个选定的值并打印它们对应的字符串表示。
$ ./enums.py friday monday thursday tuesday
Python 模式匹配元组
在下面的示例中,我们匹配元组。
#!/usr/bin/python
users = [
('John', 'Doe', 'gardener'),
('Jane', 'Doe', 'teacher'),
('Roger', 'Roe', 'driver'),
('Martin', 'Molnar', 'programmer'),
('Robert', 'Kovac', 'shopkeeper'),
('Tomas', 'Novy', 'programmer'),
]
for user in users:
match user:
case (fname, lname, 'programmer'):
print(f'{fname} {lname} is a programmer')
case (fname, lname, 'teacher'):
print(f'{fname} {lname} is a teacher')
case (fname, lname, 'gardener'):
print(f'{fname} {lname} is a gardener')
case _:
print(user)
我们有一个元组列表。每个元组是一个人及其职业。我们匹配职业。
case (fname, lname, 'programmer'):
print(f'{fname} {lname} is a programmer')
此臂将人的姓名绑定到 fname 和 lname 变量,并匹配“programmer”值。
$ ./tuples.py
John Doe is a gardener
Jane Doe is a teacher
('Roger', 'Roe', 'driver')
Martin Molnar is a programmer
('Robert', 'Kovac', 'shopkeeper')
Tomas Novy is a programmer
Python 模式匹配映射
在下一个示例中,我们进行映射的模式匹配。
#!/usr/bin/python
users = [
{'name': 'Paul', 'cols': ['red', 'blue', 'salmon']},
{'name': 'Martin', 'cols': ['blue']},
{'name': 'Lucia', 'cols': ['pink', 'brown']},
{'name': 'Jan', 'cols': ['blue', 'green']},
]
for user in users:
match user:
case {'name':name, 'cols': cols}:
print(f'favourite colours of {name}:')
for col in cols:
print(col)
我们有一个由映射表示的用户列表。
case {'name':name, 'cols': cols}:
print(f'favourite colours of {name}:')
for col in cols:
print(col)
case 臂匹配映射并打印每个用户的喜爱的颜色。
$ ./maps.py favourite colours of Paul: red blue salmon favourite colours of Martin: blue favourite colours of Lucia: pink brown favourite colours of Jan: blue green
来源
在本文中,我们研究了 Python 模式匹配。
作者
列出所有 Python 教程。