在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")