在C语言中有switch...case语句,Pthon3.10之前应该是没有类似语法,从Python3.10开始引入match...case与switch分支语句用法类似,但有细微差别,总结如下:
肉眼可见的是关键词从switch变成了match,同时match...case语句遵循Python语法风格,如下:
switch(condition)
{
case 1:
do_something_1();
break;
case 2:
do_something_2();
break;
case 3:
do_something_3();
break;
default:
do_default();
}
以上是C语言中switch...case的语法,需要注意:case后面需要有break,否则会继续执行下面的语句
match condition:
case 1:
do_something_1()
case 2:
do_something_2()
case 3:
do_something_3()
case _:
do_default()
以上是Python中match...case的语法,没有break,也没有default,取而代之的是捕捉模式(Capture),比如本例中的case _: ,与default功能类似,表示其他值,同时_相当于一个局部变量,其值等于condition,_也可以取其他变量名,当然,一个match语句中最多只能有一个捕捉模式的case,且必须位于最后一个case,就像只能有一个default一样
C语言中的case后面只能是整形值,Python的case后面可以是大部分数据类型,对于不同数据类型的匹配规则,列举如下:
数值(int,float) & 字符串(string) & None:使用等号规则进行匹配
n = -1.2
match n:
case 0: # 不匹配
print("1")
case 1: # 不匹配
print("1")
case 1.1: # 不匹配
print("1.1")
case 1.2: # 不匹配
print("1.2")
case "-1.2": # 不匹配
print("str -1.2")
case -1.2: # 匹配,且命中
print("-1.2")
case default: # 匹配,但未命中,因为前面case已经命中
print("default = " + str(default))
s = '3'
print("s == num(3) ? " + str(s == 3))
match s:
case 1: # 不匹配
print("1")
case 3: # 不匹配
print("3")
case "3": # 匹配,且命中
print("str 3")
case default: # 匹配,但未命中,因为前面case已经命中
print("default" + default)
n = None
match n:
case 0: # 不匹配
print("0")
case "": # 不匹配
print('""')
case False: # 不匹配
print("False")
case None: # 匹配,且命中
print("None")
case default: # 匹配,当未命中,因为前面case已经命中
print("default" + str(default))
布尔值(Boolean):比较特殊,True会匹配True和数字1,False会匹配False和数字0
b = True
match b:
case "": # 不匹配
print('""')
case 0: # 不匹配
print("0")
case 11: # 不匹配
print(11)
case 1: # 匹配,且命中
print(1)
case True: # 匹配,但未命中,因为前面case已经命中
print(True)
case False: # 不匹配
print(False)
case default: # 匹配,但未命中,因为前面case已经命中
print("default = " + str(default))
b = False
match b:
case "": # 不匹配
print('""')
case 0: # 匹配,且命中
print("0")
case 11: # 不匹配
print(11)
case 1: # 不匹配
print(1)
case True: # 不匹配
print(True)
case False: # 匹配,但未命中,因为前面case已经命中
print(False)
case default: # 匹配,但未命中,因为前面case已经命中
print("default = " + str(default))
字典(dictionary):当condition是个字典时,case后面只要是字典,且case后面字典的键值对在condition中都能找到,则该case命中,键值对无顺序要求,有一个比较特殊情况,假如case后面跟的是空字典,那么不管condition字典内容是什么,该case必然命中
a = {"ab":3, "5":5}
match a:
case 1: # 不匹配
print("1")
case {"ab":2}: # 不匹配
print("ab2")
case {"ab":1}: # 不匹配
print("ab1")
case {"c":3}: # 不匹配
print("c3")
case {"5":5, "ab":3}: # 匹配,且命中
print("5:5 ab:3")
case {"ab":3, "t":3}: # 不匹配
print("ab3 t3")
case {"ab":3, "5":4}: # 不匹配
print("ab3 5:4")
case {"ab":3, "5":5, "t":2}: # 不匹配
print("ab3 5:5 t2")
case {"ab":3, "5":5}: # 匹配,但未命中,因为前面case已经命中
print("ab3 5:5")
case {"ab":3}: # 匹配,但未命中,因为前面case已经命中
print("ab3")
case {}: # 匹配,但未命中,因为前面case已经命中
print("{}")
case _b: # 匹配,但未命中,因为前面case已经命中
print("_______" + str(_b))
列表 (list)& 元组(tuple):当condition是个列表或元组时,在做case比对时不分列表和元组,只要元素数量相同,且每个索引位置值相同,即可匹配成功
l = [2,3,4,5]
match l:
case 2: # 未匹配
print("2")
case 2,3: # 未匹配
print("2,3")
case 2,3,4,5,6: # 未匹配
print("2,3,4,5,6")
case [2,4,3,5]: # 未匹配
print("[2,4,3,5]")
case (2,4,3,5): # 未匹配
print("(2,4,3,5)")
case (2,3,4,5): # 匹配,且命中
print("(2,3,4,5)")
case [2,3,4,5]: # 匹配,但未命中,因为已经命中了前面的case
print("[2,3,4,5]")
case default: # 匹配,但未命中,因为已经命中了前面的case
print("default = " + str(type(default)) + str(default))
集合(set):目前似乎还不支持集合数据类型的匹配(不确定,如有错误之处,望留言指正)
类(Class):首先判断是否属于同一个class,然后判断calss各属性值是否相等
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
class Point2:
def __init__(self, x, y):
self.x = x
self.y = y
obj = Point(1,2)
match obj:
case Point(x=3, y=4): # 不匹配,属性值不相等
print("Point,3,4")
case Point2(x=1, y=2): # 不匹配,class类型不一致
print("Point2,1,2")
case {"x":1, "y":2}: # 不匹配,Class类型不一致
print("{x,y}")
case Point(x=1, y=2): # 匹配,且命中
print("Point,1,2")
case default:
print("default=" + str(default))
在C语言中,可以多个case对应一个执行过程,如下所示
switch(condition)
{
case 1:
do_something_1();
break;
case 2:
case 3:
do_something_2_3();
break;
case 4:
case 5:
do_something_4_5();
break;
default:
do_default();
}
当condition等于2或3时,执行do_sometion_2_3()函数,当condition等于4或5时,执行do_something_4_5()函数
在Python中也有类似写法,叫作组合(OR)模式,如下所示
c = 5
match c:
case 1: # 不匹配
print("1")
case 1 | 2: # 不匹配
print("1 | 2")
case 3 | 4: # 不匹配
print("3 | 4")
case 5 | 6 | 7: # 匹配,且命中
print("5 | 6 | 7")
case 5: # 匹配,但未命中,因为前面case已经命中
print("5")
case _: # 匹配,但未命中,因为前面case已经命中
print("default = " + str(_))
当捕捉模式应用到列表和字典等复杂数据类型时,情况会比较复杂,我们通过几个例子来进行说明
d = [1,2,3,4]
match d:
case a,b: # 不匹配,元素数量不等
print("a,b")
print([a,b])
case a,b,c: # 不匹配,元素数量不等
print("a,b,c")
print([a,b,c,d])
case 2,*b: # 不匹配,索引位值不相等,其中*b代表任意个元素
print("2,*b")
print(b)
case 1,*b,3: # 不匹配,索引位值不相等
print("1,*b,3")
print(b)
case *b,2: # 不匹配,索引位值不相等
print("*b,2")
print(b)
case 1,2,3,*b,4: # 匹配,且命中
print("1,2,3,*b,4")
print(b) // b = []
case 1,*b,4: # 匹配,但未命中,因为前面case已命中
print("1,*b,4")
print(b)
case *b,4: # 匹配,但未命中,因为前面case已命中
print("*b,4")
print(b)
case 1,*b: # 匹配,但未命中,因为前面case已命中
print("1,*b")
print(b)
case *b,: # 匹配,但未命中,因为前面case已命中
print("*b,")
print(b)
case [*b]: # 匹配,但未命中,因为前面case已命中
print("[*b]")
print(b)
case 2,b,c,d: # 不匹配,索引位值不相等
print("2,b,c,d")
print([2,b,c,d])
case 1,2,c,d: # 匹配,但未命中,因为前面case已命中
print("1,2,c,d")
print([1,2,c,d])
case 1,b,c,d: # 匹配,但未命中,因为前面case已命中
print("1,b,c,d")
print([1,b,c,d])
case a,b,c,d: # 匹配,但未命中,因为前面case已命中
print("a,b,c,d")
print([a,b,c,d])
case _: # 匹配,但未命中,因为前面case已命中
print("_")
本例中的a,b,c,d为捕捉模式在列表中的应用,而*b为通配符,表示匹配任意个元素,包括0个元素,且一个case中只能有一个通配符变量
类似地,捕捉模式和通配符还可以应用到字典数据类型,如下
d = {"a":1, "b":"bb", "c": [3,4], "d": {"dd":5}}
match d:
case {"s": 1}: # 不匹配
print("s:1")
case {"a":a}: # 匹配,且命中
print("a:a")
print(a) # a=1
case {"b":bbb}: # 匹配,但未命中,因为前面case已经命中
print("b:bbb")
print(bbb) # bbb = "bb"
case {"a":1, **p}: # 匹配,但未命中,因为前面case已经命中
print("a:1:**p")
print(p) # p = {"b":"bb", "c": [3,4], "d": {"dd":5}}
case {**p}: # 匹配,但未命中,因为前面case已经命中
print("**p")
print(p) # p = {"a":1, "b":"bb", "c": [3,4], "d": {"dd":5}}
case {"d":d, **p}: # 匹配,但未命中,因为前面case已经命中
print("d:d:**p")
print(p) # p = {"a":1, "b":"bb", "c": [3,4]}
case _: # 匹配,但未命中,因为前面case已经命中
print("default=" + str(default)) # default = d = {"a":1, "b":"bb", "c": [3,4], "d": {"dd":5}}
倘若要将捕捉模式和通配符用于自定义类,需要给自定义类定义一个__match_args__数组,如下
class Point:
__match_args__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
或者使用标准库的dataclasses.dataclass装饰器,它会提供__match_args__
属性,如下
from dataclasses import dataclass
@dataclass
class Point2:
x: int
y: int
这样就可以使用捕捉模式,如下
class Point:
__match_args__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
from dataclasses import dataclass
@dataclass
class Point2:
x: int
y: int
obj = Point2(1,2)
match obj:
case Point(x, y): # 不匹配,Class类型不一致
print(f'Point({x=},{y=})')
case Point2(x, y): # 匹配,且命中
print(f'Point2({x=},{y=})')
case Point(x=3, y=4): # 不匹配,Class类型不一致
print("Point,3,4")
case Point2(x=1, y=2): # 匹配,但未命中,因为前面case已经命中
print("Point2,1,2")
case {"x":1, "y":2}: # 不匹配,Class类型不一致
print("{x,y}")
case Point(x=1, y=2): # 不匹配,Class类型不一致
print("Point,1,2")
case default:# 匹配,但未命中,因为前面case已经命中
print("default=" + str(default))
简单来说就是只根据数据类型来判断是否匹配,如下
a = {1,2,3}
match a:
# case object():
# print("object")
case int(): # 不匹配
print("int")
case str(): # 不匹配
print("str")
case list(): # 不匹配
print("list")
case tuple(): # 不匹配
print("tuple")
case dict(): # 不匹配
print("dict")
case set(): # 匹配,命中
print("set")
case bool(): # 不匹配
print("bool")
case default:
print("default=" + str(type(default)) + str(default))
需要注意的是True和False会匹配int()和bool(),所有值都会匹配object
简单来说就是当匹配某个case时,将匹配到的值存入用as语句声明的新变量中,通常和数据类型匹配相结合使用,如下
a = [1,2,3,"4"]
match a:
case {"b": bb} as v: # 不匹配
print("b:bb:v")
print(bb)
print(v)
case [1, *b, int() as v]: # 不匹配
print("[1, *b]:int,v")
print(b)
print(v)
case [1, *b, str() as v]: # 匹配,命中
print("[1, *b]:str,v")
print(b) # b = [2,3]
print(v) # v = "4"
case _:
print("default = " + str(type(default)) + str(default))
可以在case后面使用if语句来添加匹配的判断条件,如下
a = [3, 4, 5, 6]
match a:
case [a, *b, c] if a>10: # 不匹配,a不大于10
print("a>10")
print("c=" + str(c))
case [a, *b, c] if a>5: # 不匹配
print("10>a>5")
print("c=" + str(c))
case [a, *b, c] if a>0: # 匹配
print("5>a>0")
print("c=" + str(c)) # c = 6
case [a, *b, c] if a<0: # 不匹配
print("a<0")
print("c=" + str(c))
case _:
print("a=0")
再比如
cmd = ["go", "away"]
match cmd:
case ["go", dir] if dir in ["east", "west"]: # 不匹配
print("go->" + dir)
case ["go", dir] if dir == "north" or dir == "south": # 不匹配
print("stop")
case ["go", dir]: # 匹配,命中
print("unknown dir:" + dir)
case _:
print("default")