# 流程控制

# if

# match-case

  • 用于模式匹配。格式如下:

    match <expression>
        case <pattern>:
            <block>
        case <pattern>:
            <block>
        ...
    
    • 执行时,会从上到下依次将 expression 与每个 case pattern 比较。如果匹配,则执行该 case block ,并结束 match-case 语句块。
  • 例:

    match 1:
        case 1:           # Literal Patterns :如果 pattern 为普通数据类型,则当 expression == pattern 时,视作匹配
            pass
        case 1:           # 允许声明重复的 case pattern
            pass
        case {1:''}:      # Mapping Patterns :如果 pattern 为 dict 类型,则当 pattern 包含于 expression 时,视作匹配
            print(1)
        case x:           # Capture Patterns :如果 pattern 为一个标识符,则视作变量,会匹配一个任意值,并赋值(称为 bind )。该变量在 match-case 语句块之后依然存在
            print(x)
    
        case 1 | 'A':             # 可以用 | 连接多个 pattern ,分别尝试匹配
            pass
        case [1, x, y] | (x, y):  # 用 | 连接的每个 pattern 中,必须使用相同数量、名称的变量,否则抛出异常:SyntaxError: alternative patterns bind different names
            pass
    
        case 1 as x:              # 可以用关键字 as 将匹配结果赋值给一个变量
            print(x)
        case [1, (2 | 3) as x]:
            pass
    
        case [1, x] if x > 0:     # 可以添加 if 条件。先判断 case pattern 是否匹配,如果匹配则绑定变量,再判断 if 条件是否成立,如果成立才执行 case block
            print(x)
        case [1, *args]:          # 支持使用 * 元组参数,匹配任意个值
            print(*args)
        case {1: _, **kwargs}:    # pattern 为 dict 类型时,支持使用 ** 字典参数
            print(kwargs)
    
        case _:                   # Wildcard Pattern :如果 pattern 只是一个 _ ,则可以匹配任意值,但不会绑定赋值给 _ 。如果 pattern 不止包含 _ ,则当作 Capture Patterns 处理
            pass
    
  • Class Patterns :如果 pattern 为一个对象,则先比较 expression、pattern 是否属于同一 class ,再比较实参列表是否相同,如果相同才算匹配。

    • pattern 不能是一个类名,否则会当作 Capture Patterns 处理。
      >>> match 1:
      ...     case str:         # 这里会把 expression 赋值给标识符 str
      ...         print(str)
      ...
      1
      
    • 内置类已经实现了 __match_args__ ,可以直接匹配。
      >>> match 1:
      ...     case int(1):
      ...         print(1)
      ...
      1
      
    • 比较实参列表时,字典参数会直接比较,而位置参数会根据 __match_args__ 转换成字典参数再比较。
      >>> class Point:
      ...     __match_args__ = ('x', 'y')
      ...     def __init__(self, x=0, y=0):
      ...         self.x = x
      ...         self.y = y
      ...
      >>>
      >>> match Point():
      ...     case Point():
      ...         print(1)
      ...
      1
      >>> match Point(1, 2):
      ...     case Point(1, y=2):
      ...         print(1)
      ...
      1
      
      • __match_args__ 取值为 tuple 类型。如果未定义,则在 case 比较时会抛出异常:TypeError: Point() accepts 0 positional sub-patterns (1 given)