1. 什么是 match
语句
match
语句可以在 Python 3.10+ 使用,学过别的 C/C++/Java 等编程语言的也许接触过多分支条件判断 switch
语句(以 C++ 举例):
int data = 123;
switch (data)
{
case 3:
cout << "data = 3!\n";
break;
case 4:
cout << "data = 4!\n";
break;
default:
cout << "The data is neither 3 nor 4!\n";
break;
}
在 Python 就可以这么写:
data = 123
match data:
case 3:
print('data = 3!')
case 4:
print('data = 4!')
case _: # 你猜它是怎么匹配的
print('The data is neither 3 nor 4')
但是它还可以……
2. 神奇的 match
语句
2.1. 匹配序列:
def match(point: tuple[int, int]) -> None: # match 是软关键字,在不合适作为关键字的时候会当作普通的变量名
match point:
case (0, 0): # 直接比较
print('O')
case (x, 0): # 可以使用变量名
print(f'{x=}')
case (0, y):
print(f'{y=}')
case (x, y):
print(f'{x=}, {y=}')
case others: # 不满足“(x, y)”,即不是二元组。
print(f'看不懂思密达: {others}')
# match 行后面没有 `:`,语境不合适,所以当作上面定义的函数
match((0, 0)) # O
match((0, 1)) # y=1
match((1, 2)) # x=1, y=2
2.2. |
def match(point: tuple[int, int]) -> None: # match 是软关键字,在不合适作为关键字的时候会当作普通的变量名
match point:
case (0, 0):
print('O')
case (x, 0) | (0, x): # 满足其中一个,| 左右必须使用相同的变量名
print(f'{x=}')
case (x, y):
print(f'{x=}, {y=}')
case others: # 不满足“(x, y)”,即不是二元组
print(f'看不懂思密达: {others}')
match((0, 1)) # x=1
match((2, 0)) # x=2
2.3. 列表的 *
def match(lst: list[int]) -> None: # match 是软关键字,在不合适作为关键字的时候会当作普通的变量名
match lst:
case []:
print('Empty')
case [1, 2, *x]: # 以 1, 2 开头
print(f'1, 2 start')
case _:
print(f'Not 1 start')
match([]) # Empty
match([1, 2, 31415926, 2178281828]) # 1, 2 start
2.4. 序列的类型
2.4.1. 一般情况不分类型
tpl = (0, 0)
lst = [0, 0]
match lst:
case (0, 0):
print('Matched!')
match lst:
case 0, 0: # (0, 0) 等价于 0, 0
print('Matched!')
match tpl:
case [0, 0]:
print('Matched!')
# 输出三行 Matched!
2.4.2. 指定类型
match [0, 0]:
case tuple(0, 0):
print('Matched tuple!') # 不输出
case list([0, 0]):
print('Matched list!') # 输出
match (0, 0):
case list: # 只关心类型
print('Matched list!') # 不输出
case tuple:
print('Matched tuple!') # 输出
此时已经体现出 match
-case
对于 if
-elif
-else
的优势。例如上面这段代码写成 if
-elif
-else
是这样:
tmp = [0, 0] # 先求值,再 case
if isinstance(tmp, tuple): # 先判断类型,在判断值
if tuple(tmp) == tuple(tuple(0, 0)):
print('Matched tuple!')
if isinstance(tmp, list):
if tuple(tmp) == tuple(list([0, 0])):
print('Matched list!')
tmp = (0, 0)
if isinstance(tmp, list):
print('Matched list!')
if isinstance(tmp, tuple):
print('Matched tuple!')
少写了好多 isinstance
捏~
2.5. guard
guard,守卫,case
-if
。
def match(point: tuple[int, int]) -> None:
match point:
case (x, y) if x > 0 and y > 0:
print(f'{x=} > 0, {y=} > 0')
case (x, y): # 其他情况
print(f'{x=}, {y=}')
match((1, 2)) # x=1 > 0, y=2 > 0
match((-1, 3)) # x=-1, y=3
2.6. 匹配字典
d = {'a': 1, 'b': 2, 'c': 3}
match d:
case {'a': a, 'b': y, 'c': 3}: # 匹配成功
print(f'a: {a}, b: {y}, c: 3')
match d:
case {'a': 1, 'b': y}: # 子字典即可
print('a: 1, b: {y}!')
match d:
case {}: # 空字典是任何字典的子字典,所以相当于 case dict:
print('Dict!')
2.7. 匹配自定义类
2.7.1. 一般情况
class A:
def __init__(self, x, y):
self.x = x
self.y = y
match A(0, 0):
# case A(x, y=y): # 报错
case A(x=x, y=y): # 必须要这样写
print(f'A({x=}, {y=})')
2.7.2. __match_args__
class A:
__match_args__ = ('x')
def __init__(self, x, y):
self.x = x
self.y = y
match A(0, 0):
# case A(0, 0): # 报错
case A(x, y=y): # 或者写成 case A(x=x, y=y):
print(f'A({x}, {y=})')
3. 总结
参考:https://huccihuang.github.io/posts/Match-case/