开放的编程资料库

当前位置:我爱分享网 > Python教程 > 正文

Python 模式匹配

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

我们有三个类:CatDogPerson。通过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')

这个手臂将人名绑定到fnamelname变量,并匹配“程序员”值。

$ ./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教程。

未经允许不得转载:我爱分享网 » Python 模式匹配

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏