• Python中match...case的用法


    在C语言中有switch...case语句,Pthon3.10之前应该是没有类似语法,从Python3.10开始引入match...case与switch分支语句用法类似,但有细微差别,总结如下:

    1.语法

    肉眼可见的是关键词从switch变成了match,同时match...case语句遵循Python语法风格,如下:

    1. switch(condition)
    2. {
    3. case 1
    4. do_something_1();
    5. break;
    6. case 2:
    7. do_something_2();
    8. break;
    9. case 3:
    10. do_something_3();
    11. break;
    12. default:
    13. do_default();
    14. }

    以上是C语言中switch...case的语法,需要注意:case后面需要有break,否则会继续执行下面的语句

    1. match condition:
    2. case 1:
    3. do_something_1()
    4. case 2:
    5. do_something_2()
    6. case 3:
    7. do_something_3()
    8. case _:
    9. do_default()

    以上是Python中match...case的语法,没有break,也没有default,取而代之的是捕捉模式(Capture),比如本例中的case _: ,与default功能类似,表示其他值,同时_相当于一个局部变量,其值等于condition,_也可以取其他变量名,当然,一个match语句中最多只能有一个捕捉模式的case,且必须位于最后一个case,就像只能有一个default一样

    2.数据类型支持

    C语言中的case后面只能是整形值,Python的case后面可以是大部分数据类型,对于不同数据类型的匹配规则,列举如下:

    数值(int,float) & 字符串(string) & None:使用等号规则进行匹配

    1. n = -1.2
    2. match n:
    3. case 0: # 不匹配
    4. print("1")
    5. case 1: # 不匹配
    6. print("1")
    7. case 1.1: # 不匹配
    8. print("1.1")
    9. case 1.2: # 不匹配
    10. print("1.2")
    11. case "-1.2": # 不匹配
    12. print("str -1.2")
    13. case -1.2: # 匹配,且命中
    14. print("-1.2")
    15. case default: # 匹配,但未命中,因为前面case已经命中
    16. print("default = " + str(default))
    1. s = '3'
    2. print("s == num(3) ? " + str(s == 3))
    3. match s:
    4. case 1: # 不匹配
    5. print("1")
    6. case 3: # 不匹配
    7. print("3")
    8. case "3": # 匹配,且命中
    9. print("str 3")
    10. case default: # 匹配,但未命中,因为前面case已经命中
    11. print("default" + default)
    1. n = None
    2. match n:
    3. case 0: # 不匹配
    4. print("0")
    5. case "": # 不匹配
    6. print('""')
    7. case False: # 不匹配
    8. print("False")
    9. case None: # 匹配,且命中
    10. print("None")
    11. case default: # 匹配,当未命中,因为前面case已经命中
    12. print("default" + str(default))

    布尔值(Boolean):比较特殊,True会匹配True和数字1,False会匹配False和数字0

    1. b = True
    2. match b:
    3. case "": # 不匹配
    4. print('""')
    5. case 0: # 不匹配
    6. print("0")
    7. case 11: # 不匹配
    8. print(11)
    9. case 1: # 匹配,且命中
    10. print(1)
    11. case True: # 匹配,但未命中,因为前面case已经命中
    12. print(True)
    13. case False: # 不匹配
    14. print(False)
    15. case default: # 匹配,但未命中,因为前面case已经命中
    16. print("default = " + str(default))
    1. b = False
    2. match b:
    3. case "": # 不匹配
    4. print('""')
    5. case 0: # 匹配,且命中
    6. print("0")
    7. case 11: # 不匹配
    8. print(11)
    9. case 1: # 不匹配
    10. print(1)
    11. case True: # 不匹配
    12. print(True)
    13. case False: # 匹配,但未命中,因为前面case已经命中
    14. print(False)
    15. case default: # 匹配,但未命中,因为前面case已经命中
    16. print("default = " + str(default))

    字典(dictionary):当condition是个字典时,case后面只要是字典,且case后面字典的键值对在condition中都能找到,则该case命中,键值对无顺序要求,有一个比较特殊情况,假如case后面跟的是空字典,那么不管condition字典内容是什么,该case必然命中

    1. a = {"ab":3, "5":5}
    2. match a:
    3. case 1: # 不匹配
    4. print("1")
    5. case {"ab":2}: # 不匹配
    6. print("ab2")
    7. case {"ab":1}: # 不匹配
    8. print("ab1")
    9. case {"c":3}: # 不匹配
    10. print("c3")
    11. case {"5":5, "ab":3}: # 匹配,且命中
    12. print("5:5 ab:3")
    13. case {"ab":3, "t":3}: # 不匹配
    14. print("ab3 t3")
    15. case {"ab":3, "5":4}: # 不匹配
    16. print("ab3 5:4")
    17. case {"ab":3, "5":5, "t":2}: # 不匹配
    18. print("ab3 5:5 t2")
    19. case {"ab":3, "5":5}: # 匹配,但未命中,因为前面case已经命中
    20. print("ab3 5:5")
    21. case {"ab":3}: # 匹配,但未命中,因为前面case已经命中
    22. print("ab3")
    23. case {}: # 匹配,但未命中,因为前面case已经命中
    24. print("{}")
    25. case _b: # 匹配,但未命中,因为前面case已经命中
    26. print("_______" + str(_b))

    列表 (list)& 元组(tuple):当condition是个列表或元组时,在做case比对时不分列表和元组,只要元素数量相同,且每个索引位置值相同,即可匹配成功

    1. l = [2,3,4,5]
    2. match l:
    3. case 2: # 未匹配
    4. print("2")
    5. case 2,3: # 未匹配
    6. print("2,3")
    7. case 2,3,4,5,6: # 未匹配
    8. print("2,3,4,5,6")
    9. case [2,4,3,5]: # 未匹配
    10. print("[2,4,3,5]")
    11. case (2,4,3,5): # 未匹配
    12. print("(2,4,3,5)")
    13. case (2,3,4,5): # 匹配,且命中
    14. print("(2,3,4,5)")
    15. case [2,3,4,5]: # 匹配,但未命中,因为已经命中了前面的case
    16. print("[2,3,4,5]")
    17. case default: # 匹配,但未命中,因为已经命中了前面的case
    18. print("default = " + str(type(default)) + str(default))

    集合(set):目前似乎还不支持集合数据类型的匹配(不确定,如有错误之处,望留言指正)

    类(Class):首先判断是否属于同一个class,然后判断calss各属性值是否相等

    1. class Point:
    2. def __init__(self, x, y):
    3. self.x = x
    4. self.y = y
    5. class Point2:
    6. def __init__(self, x, y):
    7. self.x = x
    8. self.y = y
    9. obj = Point(1,2)
    10. match obj:
    11. case Point(x=3, y=4): # 不匹配,属性值不相等
    12. print("Point,3,4")
    13. case Point2(x=1, y=2): # 不匹配,class类型不一致
    14. print("Point2,1,2")
    15. case {"x":1, "y":2}: # 不匹配,Class类型不一致
    16. print("{x,y}")
    17. case Point(x=1, y=2): # 匹配,且命中
    18. print("Point,1,2")
    19. case default:
    20. print("default=" + str(default))

    3.组合case

    在C语言中,可以多个case对应一个执行过程,如下所示

    1. switch(condition)
    2. {
    3. case 1
    4. do_something_1();
    5. break;
    6. case 2:
    7. case 3:
    8. do_something_2_3();
    9. break;
    10. case 4:
    11. case 5:
    12. do_something_4_5();
    13. break;
    14. default:
    15. do_default();
    16. }

    当condition等于2或3时,执行do_sometion_2_3()函数,当condition等于4或5时,执行do_something_4_5()函数

    在Python中也有类似写法,叫作组合(OR)模式,如下所示

    1. c = 5
    2. match c:
    3. case 1: # 不匹配
    4. print("1")
    5. case 1 | 2: # 不匹配
    6. print("1 | 2")
    7. case 3 | 4: # 不匹配
    8. print("3 | 4")
    9. case 5 | 6 | 7: # 匹配,且命中
    10. print("5 | 6 | 7")
    11. case 5: # 匹配,但未命中,因为前面case已经命中
    12. print("5")
    13. case _: # 匹配,但未命中,因为前面case已经命中
    14. print("default = " + str(_))

    4.通配符,捕捉模式的扩展

    当捕捉模式应用到列表和字典等复杂数据类型时,情况会比较复杂,我们通过几个例子来进行说明

    1. d = [1,2,3,4]
    2. match d:
    3. case a,b: # 不匹配,元素数量不等
    4. print("a,b")
    5. print([a,b])
    6. case a,b,c: # 不匹配,元素数量不等
    7. print("a,b,c")
    8. print([a,b,c,d])
    9. case 2,*b: # 不匹配,索引位值不相等,其中*b代表任意个元素
    10. print("2,*b")
    11. print(b)
    12. case 1,*b,3: # 不匹配,索引位值不相等
    13. print("1,*b,3")
    14. print(b)
    15. case *b,2: # 不匹配,索引位值不相等
    16. print("*b,2")
    17. print(b)
    18. case 1,2,3,*b,4: # 匹配,且命中
    19. print("1,2,3,*b,4")
    20. print(b) // b = []
    21. case 1,*b,4: # 匹配,但未命中,因为前面case已命中
    22. print("1,*b,4")
    23. print(b)
    24. case *b,4: # 匹配,但未命中,因为前面case已命中
    25. print("*b,4")
    26. print(b)
    27. case 1,*b: # 匹配,但未命中,因为前面case已命中
    28. print("1,*b")
    29. print(b)
    30. case *b,: # 匹配,但未命中,因为前面case已命中
    31. print("*b,")
    32. print(b)
    33. case [*b]: # 匹配,但未命中,因为前面case已命中
    34. print("[*b]")
    35. print(b)
    36. case 2,b,c,d: # 不匹配,索引位值不相等
    37. print("2,b,c,d")
    38. print([2,b,c,d])
    39. case 1,2,c,d: # 匹配,但未命中,因为前面case已命中
    40. print("1,2,c,d")
    41. print([1,2,c,d])
    42. case 1,b,c,d: # 匹配,但未命中,因为前面case已命中
    43. print("1,b,c,d")
    44. print([1,b,c,d])
    45. case a,b,c,d: # 匹配,但未命中,因为前面case已命中
    46. print("a,b,c,d")
    47. print([a,b,c,d])
    48. case _: # 匹配,但未命中,因为前面case已命中
    49. print("_")

    本例中的a,b,c,d为捕捉模式在列表中的应用,而*b为通配符,表示匹配任意个元素,包括0个元素,且一个case中只能有一个通配符变量

    类似地,捕捉模式和通配符还可以应用到字典数据类型,如下

    1. d = {"a":1, "b":"bb", "c": [3,4], "d": {"dd":5}}
    2. match d:
    3. case {"s": 1}: # 不匹配
    4. print("s:1")
    5. case {"a":a}: # 匹配,且命中
    6. print("a:a")
    7. print(a) # a=1
    8. case {"b":bbb}: # 匹配,但未命中,因为前面case已经命中
    9. print("b:bbb")
    10. print(bbb) # bbb = "bb"
    11. case {"a":1, **p}: # 匹配,但未命中,因为前面case已经命中
    12. print("a:1:**p")
    13. print(p) # p = {"b":"bb", "c": [3,4], "d": {"dd":5}}
    14. case {**p}: # 匹配,但未命中,因为前面case已经命中
    15. print("**p")
    16. print(p) # p = {"a":1, "b":"bb", "c": [3,4], "d": {"dd":5}}
    17. case {"d":d, **p}: # 匹配,但未命中,因为前面case已经命中
    18. print("d:d:**p")
    19. print(p) # p = {"a":1, "b":"bb", "c": [3,4]}
    20. case _: # 匹配,但未命中,因为前面case已经命中
    21. print("default=" + str(default)) # default = d = {"a":1, "b":"bb", "c": [3,4], "d": {"dd":5}}

    倘若要将捕捉模式和通配符用于自定义类,需要给自定义类定义一个__match_args__数组,如下

    1. class Point:
    2. __match_args__ = ('x', 'y')
    3. def __init__(self, x, y):
    4. self.x = x
    5. self.y = y

    或者使用标准库的dataclasses.dataclass装饰器,它会提供__match_args__属性,如下

    1. from dataclasses import dataclass
    2. @dataclass
    3. class Point2:
    4. x: int
    5. y: int

    这样就可以使用捕捉模式,如下

    1. class Point:
    2. __match_args__ = ('x', 'y')
    3. def __init__(self, x, y):
    4. self.x = x
    5. self.y = y
    6. from dataclasses import dataclass
    7. @dataclass
    8. class Point2:
    9. x: int
    10. y: int
    11. obj = Point2(1,2)
    12. match obj:
    13. case Point(x, y): # 不匹配,Class类型不一致
    14. print(f'Point({x=},{y=})')
    15. case Point2(x, y): # 匹配,且命中
    16. print(f'Point2({x=},{y=})')
    17. case Point(x=3, y=4): # 不匹配,Class类型不一致
    18. print("Point,3,4")
    19. case Point2(x=1, y=2): # 匹配,但未命中,因为前面case已经命中
    20. print("Point2,1,2")
    21. case {"x":1, "y":2}: # 不匹配,Class类型不一致
    22. print("{x,y}")
    23. case Point(x=1, y=2): # 不匹配,Class类型不一致
    24. print("Point,1,2")
    25. case default:# 匹配,但未命中,因为前面case已经命中
    26. print("default=" + str(default))

    5.数据类型匹配

    简单来说就是只根据数据类型来判断是否匹配,如下

    1. a = {1,2,3}
    2. match a:
    3. # case object():
    4. # print("object")
    5. case int(): # 不匹配
    6. print("int")
    7. case str(): # 不匹配
    8. print("str")
    9. case list(): # 不匹配
    10. print("list")
    11. case tuple(): # 不匹配
    12. print("tuple")
    13. case dict(): # 不匹配
    14. print("dict")
    15. case set(): # 匹配,命中
    16. print("set")
    17. case bool(): # 不匹配
    18. print("bool")
    19. case default:
    20. print("default=" + str(type(default)) + str(default))

    需要注意的是True和False会匹配int()和bool(),所有值都会匹配object

    6.AS语法

    简单来说就是当匹配某个case时,将匹配到的值存入用as语句声明的新变量中,通常和数据类型匹配相结合使用,如下

    1. a = [1,2,3,"4"]
    2. match a:
    3. case {"b": bb} as v: # 不匹配
    4. print("b:bb:v")
    5. print(bb)
    6. print(v)
    7. case [1, *b, int() as v]: # 不匹配
    8. print("[1, *b]:int,v")
    9. print(b)
    10. print(v)
    11. case [1, *b, str() as v]: # 匹配,命中
    12. print("[1, *b]:str,v")
    13. print(b) # b = [2,3]
    14. print(v) # v = "4"
    15. case _:
    16. print("default = " + str(type(default)) + str(default))

    7.补充条件模式

    可以在case后面使用if语句来添加匹配的判断条件,如下

    1. a = [3, 4, 5, 6]
    2. match a:
    3. case [a, *b, c] if a>10: # 不匹配,a不大于10
    4. print("a>10")
    5. print("c=" + str(c))
    6. case [a, *b, c] if a>5: # 不匹配
    7. print("10>a>5")
    8. print("c=" + str(c))
    9. case [a, *b, c] if a>0: # 匹配
    10. print("5>a>0")
    11. print("c=" + str(c)) # c = 6
    12. case [a, *b, c] if a<0: # 不匹配
    13. print("a<0")
    14. print("c=" + str(c))
    15. case _:
    16. print("a=0")

    再比如

    1. cmd = ["go", "away"]
    2. match cmd:
    3. case ["go", dir] if dir in ["east", "west"]: # 不匹配
    4. print("go->" + dir)
    5. case ["go", dir] if dir == "north" or dir == "south": # 不匹配
    6. print("stop")
    7. case ["go", dir]: # 匹配,命中
    8. print("unknown dir:" + dir)
    9. case _:
    10. print("default")

  • 相关阅读:
    C#——文件读取Directory类详情
    PayPal VS Block:开启全球金融科技的新未来
    MySQL的结构化语言 DDL DML DQL DCL
    文章解读与仿真程序复现思路——中国电机工程学报EI\CSCD\北大核心《计及电动汽车需求响应的高速公路服务区光储充鲁棒优化配置》
    Android Jetpack组件架构:ViewModel的原理
    IgH详解十四、igh添加总线链路状态监测功能
    express学习40-多人管理31数据分页2
    vue当中的mapState 使用
    【老生谈算法】matlab实现聚类分析源码——聚类分析
    GAMES101 PA3
  • 原文地址:https://blog.csdn.net/ctbinzi/article/details/133219015