来了,他来了,他终于来了!_元组


前言

众所周知,大多数语言都有 ​​switch-case​​​ 语句,但是作为红极一时的 Python,它却没有。今天,它终于来了。2021 年 2 月 8 日,指导委员会通过了 ​​PEP 634, PEP635, PEP636​​​,至此,Python 总算拥有了功能和 ​​switch-case​​​ 相同的 ​​match-case​​​, 我们再也不用再写一连串的 ​​if-else​​ 了。

展示

单个匹配

即用一个参数同多种属性进行比较。

def http_error(status):
match status:
case 400:
return "Bad request"
case 401:
return "not auth"
case 403:
return "not allow"
case 404:
return "not found"
case 418:
return "418"
case _:
return "else"

如上,其中 ​​case _​​​意为当其他 ​​case​​ 都无法匹配时,就匹配这条,可以达到永远不会匹配失败的效果。

多个匹配

即使用 ​​|​​ 将多个匹配值组合起来。

...
case 401|403|404:
return "err"

模式匹配

模式也可以是解包操作,用于绑定变量。

# 主题表达式是一个(x, y)元组
match point:
case (0, 0):
print("00")
case (0, y):
print("0y")
case (x, 0):
print("x0")
case (x, y):
print("xy")
case _:
raise ValueError("err")

注意,第一个模式中有两个字面量,可以看作是上述普通模式的加强版。但是后两个模式有些不同,元组中一个是字面量一个是变量,这个变量会捕获主题元组中的值。同理,第四个模式 ​​case (x, y)​​​ 会捕获两个值,这在理论上与解包作业相似,就如同 ​​point(x, y) = point​​。

数据类型匹配

如果使用了结构数据类,比如 ​​dataclasses​​​,可以用类似于构造函数 ​​类名+参数列表​​ 的形式,但是用来捕获变量。

from dataclasses import dataclass

@dataclass
class Point:
x: int
y: int

def whereis(point):
match point:
case Point(0, 0):
print("00")
case Point(0, y):
print("0y")
case Point(x, 0):
print("x0")
case Point():
print("P")
case _:
print("else")

关键字参数匹配

也可以使用关键字参数。下列关于 ​​y, var​​ 的模式都是等价的,并且都将属性绑定到了变量上。

Point(1, var)
Point(1, y=var)
Point(x=1, y=var)
Point(y=var, x=1)

模式嵌套

模式可以被简单粗暴的嵌套起来,例如我们有一组 ​​points​​ 的列表,就可以像这样匹配。

match points:
case []:
print("none")
case [Point(0, 0)]:
print("00")
case [Point(x, y)]:
print("xy")
case [Point(0, y1), Point(0, y2)]:
print(f"y1,y2")
case _:
print("else")

条件模式

给模式添加 ​​if​​​ 从句以充当门卫。如果为假,就移步到下一个 ​​case​​。注意,模式捕获值发生在从句执行前。

match point:
case Point(x, y) if x == y:
print("x==y")
case Point(x, y):
print("x!=y")

子模式

子模式可以使用 ​​as​​ 捕获。

case (Point(x1, y1), Point(x2, y2) as p2): ...

常量模式

模式可以使用命名的常量,且必须使用​​.​​以防止被解释为捕获变量。

from enum import Enum
class Color(Enum):
RED = 0
GREEN = 1
BLUE = 2

match color:
case Color.RED:
print("red!")
case Color.GREEN:
print("green")
case Color.BLUE:
print("blue")

等同 is

某些字面量会被特殊对待,例如 ​​None, False, True​​​,是使用 ​​is​​ 完成匹配的。

例如:

match b:
case True:
print("ok!")

就完全等价与这样

...
if b is True:
print("ok!")