LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 224|回复: 0

pass 语句 与 match 语句

[复制链接]
发表于 2023-12-22 16:56:12 | 显示全部楼层 |阅读模式

pass 语句

pass 语句不执行任何动作。语法上需要一个语句,但程序毋需执行任何动作时,可以使用该语句。例如:

>>>
while True:
    pass  # Busy-wait for keyboard interrupt (Ctrl+C)

这常用于创建一个最小的类:

>>>
class MyEmptyClass:
    pass

pass 还可用作函数或条件语句体的占位符,让你保持在更抽象的层次进行思考。pass 会被默默地忽略:

>>>
def initlog(*args):
    pass   # Remember to implement this!



match 语句

match 语句接受一个表达式并把它的值与一个或多个 case 块给出的一系列模式进行比较。这表面上像 C、Java 或 JavaScript(以及许多其他程序设计语言)中的 switch 语句,但其实它更像 Rust 或 Haskell 中的模式匹配。只有第一个匹配的模式会被执行,并且它还可以提取值的组成部分(序列的元素或对象的属性)赋给变量。

最简单的形式是将一个主语值与一个或多个字面值进行比较:

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"
        case _:
            return "Something's wrong with the internet"
注意最后一个代码块:“变量名” _ 被作为 通配符 并必定会匹配成功。如果没有 case 匹配成功,则不会执行任何分支。

你可以用 | (“或”)将多个字面值组合到一个模式中:

case 401 | 403 | 404:
    return "Not allowed"
形如解包赋值的模式可被用于绑定变量:

# point is an (x, y) tuple
match point:
    case (0, 0):
        print("Origin")
    case (0, y):
        print(f"Y={y}")
    case (x, 0):
        print(f"X={x}")
    case (x, y):
        print(f"X={x}, Y={y}")
    case _:
        raise ValueError("Not a point")
请仔细学习此代码!第一个模式有两个字面值,可视为前述字面值模式的扩展。接下来的两个模式结合了一个字面值和一个变量,变量 绑定 了来自主语(point)的一个值。第四个模式捕获了两个值,使其在概念上与解包赋值 (x, y) = point 类似。

如果用类组织数据,可以用“类名后接一个参数列表”这种很像构造器的形式,把属性捕获到变量里:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

def where_is(point):
    match point:
        case Point(x=0, y=0):
            print("Origin")
        case Point(x=0, y=y):
            print(f"Y={y}")
        case Point(x=x, y=0):
            print(f"X={x}")
        case Point():
            print("Somewhere else")
        case _:
            print("Not a point")
一些内置类(如 dataclass)为属性提供了一个顺序,此时,可以使用位置参数。自定义类可通过在类中设置特殊属性 __match_args__,为属性指定其在模式中对应的位置。若设为 ("x", "y"),则以下模式相互等价(且都把属性 y 绑定到变量 var):

Point(1, var)
Point(1, y=var)
Point(x=1, y=var)
Point(y=var, x=1)
建议这样来阅读一个模式——通过将其视为赋值语句等号左边的一种扩展形式,来理解各个变量被设为何值。match 语句只会为单一的名称(如上面的 var)赋值,而不会赋值给带点号的名称(如 foo.bar)、属性名(如上面的 x= 和 y=)和类名(是通过其后的 "(...)" 来识别的,如上面的 Point)。

模式可以任意嵌套。举例来说,如果我们有一个由 Point 组成的列表,且 Point 添加了 __match_args__ 时,我们可以这样来匹配它:

class Point:
    __match_args__ = ('x', 'y')
    def __init__(self, x, y):
        self.x = x
        self.y = y

match points:
    case []:
        print("No points")
    case [Point(0, 0)]:
        print("The origin")
    case [Point(x, y)]:
        print(f"Single point {x}, {y}")
    case [Point(0, y1), Point(0, y2)]:
        print(f"Two on the Y axis at {y1}, {y2}")
    case _:
        print("Something else")
我们可以为模式添加 if 作为守卫子句。如果守卫子句的值为假,那么 match 会继续尝试匹配下一个 case 块。注意是先将值捕获,再对守卫子句求值:

match point:
    case Point(x, y) if x == y:
        print(f"Y=X at {x}")
    case Point(x, y):
        print(f"Not on the diagonal")
该语句的一些其它关键特性:

与解包赋值类似,元组和列表模式具有完全相同的含义并且实际上都能匹配任意序列,区别是它们不能匹配迭代器或字符串。

序列模式支持扩展解包:[x, y, *rest] 和 (x, y, *rest) 和相应的解包赋值做的事是一样的。接在 * 后的名称也可以为 _,所以 (x, y, *_) 匹配含至少两项的序列,而不必绑定剩余的项。

映射模式:{"bandwidth": b, "latency": l} 从字典中捕获 "bandwidth" 和 "latency" 的值。额外的键会被忽略,这一点与序列模式不同。**rest 这样的解包也支持。(但 **_ 将会是冗余的,故不允许使用。)

使用 as 关键字可以捕获子模式:

case (Point(x1, y1), Point(x2, y2) as p2): ...
将把输入中的第二个元素捕获为 p2 (只要输入是包含两个点的序列)

大多数字面值是按相等性比较的,但是单例对象 True、False 和 None 则是按 id 比较的。

模式可以使用具名常量。它们必须作为带点号的名称出现,以防止它们被解释为用于捕获的变量:


  1. from enum import Enum
  2. class Color(Enum):
  3.     RED = 'red'
  4.     GREEN = 'green'
  5.     BLUE = 'blue'

  6. color = Color(input("Enter your choice of 'red', 'blue' or 'green': "))

  7. match color:
  8.     case Color.RED:
  9.         print("I see red!")
  10.     case Color.GREEN:
  11.         print("Grass is green")
  12.     case Color.BLUE:
  13.         print("I'm feeling the blues :(")
复制代码


您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表