在本文中,我们展示了如何在Python中使用模式匹配。
模式匹配是通过match/case关键字完成的。它在Python3.10中以结构模式匹配的名称引入。
模式匹配是一种强大的控制流结构,它允许我们将一个值与一系列模式进行比较,然后根据匹配的模式执行代码。它是一种比if/elsestatements或经典的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')
这只手臂检查人物体。
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变量,并匹配“程序员”值。
$ ./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教程。
