在本文中,我们展示了如何在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教程。