Python 中 switch/case 的语法等价物是什么?

fam*_*man 12 python syntax pattern-matching switch-statement conditional-statements

C/C++、C#、Java、JavaScript 和 Pascal 参考等编程语言具有switchandcase语句(有时也称为selector inspect)的组合,允许您根据多个条件检查一个值以执行某些操作。

my_value = 10;
switch(my_value) {
    case 10:
        print("The number is ten");
    case 2*10:
        print("The number is the double of ten");
    case 100:
        print("The number is one hundred");
    default:
        print("The number is none of 10, 2*10 or 100");
}
Run Code Online (Sandbox Code Playgroud)

描述switch-case结构的特殊语法的伪代码。

意识到像dictionary-lookups这样的功能等价物,是否有与上述编程结构完全相同的语法

fam*_*man 23

TL; 博士

Python 3.10.0 (alpha62021 年 3 月 30 日发布)开始,Python 有一个官方的等效语法,称为match.

基本语法是:

match value:
    case condition:
        action(s)
    ...
Run Code Online (Sandbox Code Playgroud)

对于较旧的 Python 版本,如果您不想诉诸if- elif- ,则只有解决方法else
请参阅此优秀社区帖子以获取其中的一些集合。

例子

my_value = 10
match my_value:
    case 10:
        print("The number is ten")
    case 2*10:
        print("The number is the double of ten")
    case 100:
        print("The number is one hundred")
    case _:
        # this is the default handler if none
        # of the above cases match.
        print("The number is none of 10, 2*10 or 100")
Run Code Online (Sandbox Code Playgroud)

因此,涉及变通方法的其他答案不再有效 - 从性能的角度来看也是如此。

重要通知

如果来自支持switch和 的语言case,您可能已经了解它们的行为。但是,对于 Python,有一些差异需要注意。

  • 案例不会失败
    带有switch-case语句的语言执行每个值匹配的案例 - 从上到下是很常见的。因此,如果您不想失败,还有第三个语句 -break用于switch-case结构:

    value = 10
    switch (value) {
        case 10:
            print("Value is ten");
        case 2*5:
            print("Value is the double of five");
            break;
        case 20/2:
            print("Value is the half of twenty");
        default:
            print("This is just the default action.");
    }
    
    Run Code Online (Sandbox Code Playgroud)

    在此示例中,将执行前两个案例,因为第一个案例失败了。如果break第二个 case中没有语句,则将执行所有 case,包括默认 case。

    在 Python 中,只执行第一个匹配的案例。你可以把它想象成每个案例都包含一个隐藏的break语句。

  • 变量引用不能作为条件

    value = 10
    switch (value) {
        case 10:
            print("Value is ten");
        case 2*5:
            print("Value is the double of five");
            break;
        case 20/2:
            print("Value is the half of twenty");
        default:
            print("This is just the default action.");
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这段代码确实打印出颜色匹配!

    作为 case 条件的裸变量引用将始终匹配。

    无论如何,文字case "red": ...限定(即加点)名称case AllColors.red都像预期的那样工作 - 无需害怕它们。

    所有这一切都是如此,因为 Python 软件基金会并没有决定只是复制另一个无聊的控制流模型,而是实际实现一个成熟的模式匹配器,它不仅仅是一个switch-case语句。在下一节中可以找到更多关于此的信息。

强大的模式匹配

match-中号ATCH一个 Ç ASE ħ ooey

Python 增强提案 (PEP) 编号中提供的规范和信息。634-636

在 Python 中,match实际上不仅仅是一个简单的开关——因此可能是这个名字。它具有特殊功能,如深占位符和通配符。

通过阅读文档启发的示例 - 因此您不必:

base_color = "red"
chosen_color = "green"
match chosen_color:
    case base_color:
        print("Yes, it matches!")
Run Code Online (Sandbox Code Playgroud)

您可以匹配任意嵌套的数据结构,包括占位符。在上面的例子中,我们将一个元组与两个项目匹配,在第二种情况下,我们使用一个占位符y,在匹配时获得其分配的值。

您还可以以非常相似的方式匹配类属性:

match point:
    case (0, 0):
        print("Origin")
    case (0, y):
        print("Our current Y position is", y, " now.")
Run Code Online (Sandbox Code Playgroud)

这也解释了为什么您不能在 case 条件下匹配单个变量引用:您实际上并没有匹配该变量的值,而是实际上引入了一个同名的占位符!因此,如果您要chosen_color像这样打印:

class Point:
    x: int
    y: int

def location(point):
    match point:
        case Point(x=0, y=0):
            print("Origin is the point's location.")
        case Point(x=0, y=y):
            print("The point lies on the y axis at a height of", y, "units.")
Run Code Online (Sandbox Code Playgroud)

它实际上会打印出来

我们的基色是绿色

因为base_color现在是一个占位符,它被分配了我们的chosen_color.

这种高级模式匹配还有更多用例,Python 文档中提到了其中一些有趣的用例。

结语

Python 3.10 得到应有的采用需要时间。Python 3.10.0 将于202110 月 4 日稳定发布- 这意味着它可能包含在 Ubuntu 22.04 及更高版本中。

如果您只是想自己玩玩和编写程序,将它们部署到您自己的服务器上,或者如果您打算以打包形式分发您的作品而不是作为普通的源代码文件,请在您的程序中尝试这个新功能 -这将是一个好处!

附录

尝试 Python 3.10.0

对于 Windows 和 MacOS 用户,此页面提供官方安装程序下载。

在 Debian 和 Ubuntu 上,您可以使用非常流行的“DeadSnakes”项目 PPA:

base_color = "red"
chosen_color = "green"
match chosen_color:
    case base_color:
        print("Our base color is", base_color)
Run Code Online (Sandbox Code Playgroud)

在不破坏系统的情况下尝试 Python 3.10.0

Docker是使用 Python 3.10 的一种选择,无需任何复杂的设置步骤,并且在完全隔离的环境中。

docker run -it python:3.10.0a6-alpine

就是这样。随着时间的推移,可能会发布新的 alpha 或 beta 版本。然后您将需要a6不同的版本替换。

  • 我正要评论说这似乎是一个完美的时机问题(考虑到阿尔法发布还不到一天),然后我注意到你自己回答了它!很好的答案,感谢您将其添加到 SO python 知识库中。:) (2认同)

Hra*_*bal 12

Python 3.10.0 之前的答案

那没有。通常有两种方式完成,具体取决于代码上下文:

1. if/elif:

使用 if/elif 语法,您可以获得最相似版本的 switch case:

my_value = 10;
if my_value == 10:
    print("The number is ten")
elif my_value == 2*10:
    print("The number is the double of ten")
elif my_value == 100:
    print("The number is one hundred")
else:
    print("The number is none of 10, 2*10 or 100")
Run Code Online (Sandbox Code Playgroud)

2. 字典查找:

另一种不太常见的方法是创建一个字典并在 switch/case 的每个条件下分配一个要调用的相应函数:

my_value = 10;

def def_action():
    print("The number is none of 10, 2*10 or 100")

def ten_action():
    print("The number is ten")

def double_ten_action():
    print("The number is ten")

def hundred_action():
    print("The number is one hundred")

{
    10: ten_action,
    2*10: double_ten_action,
    100: hundred_action,
}.get(
    my_value,
    def_action # This is the final else, if no match if found
)()
Run Code Online (Sandbox Code Playgroud)

尽管Pythonic较少,但当在各种情况下您有大量代码导致可读性变差时,这很有用。