问题描述
C/C++、C#、Java、JavaScript 和 Pascal 等编程语言 (Reference) 结合了 switch
和 case
语句(有时也称为 select
或 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");
}
了解 dictionary-lookups 等功能等价物后,是否存在与上述编程结构完全相同的语法等价物?
解决方法
TL;DR
从 Python 3.10.0 (alpha6 released March 30,2021) 开始,Python 有一个官方的等效语法,称为 match
。
基本语法是:
match value:
case condition:
action(s)
...
对于较旧的 Python 版本,只有在您不想求助于 if
-elif
-else
时才有解决方法。
请参阅此出色的 community post 以获取其中一些集合。
示例
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")
因此,涉及变通方法的其他答案不再有效 - 从性能的角度来看也是如此。
重要通知
如果来自支持 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."); }
在此示例中,将执行前 两个 案例,因为第一个案例失败了。如果第二个 case 中没有
break
语句,则将执行所有 case,包括默认 case。在 Python 中,只执行第一个匹配的 case。您可以将其视为每个案例都包含一个隐藏的
break
语句。 -
变量引用不能作为条件
base_color = "red" chosen_color = "green" match chosen_color: case base_color: print("Yes,it matches!")
此代码确实打印出颜色匹配!
作为 case 条件的裸变量引用将始终匹配。
无论如何,像
case "red": ...
和 qualified(即虚线)名称这样的文字如case AllColors.red
都按预期工作 - 无需害怕它们。所有这一切都是如此,因为 Python 软件基金会并没有决定只是复制另一个无聊的控制流模型,而是真正实现了一个成熟的模式匹配器,它不仅仅是一个
switch
-case
语句。更多相关信息,请参见下一节。
强大的模式匹配
match
- Match ain't case h哎呀
Python Enhancement Proposals (PEP) nos. 634-636
中提供的规范和信息在 Python 中,match
实际上不仅仅是一个简单的开关 - 因此可能是名称。它具有特殊功能,例如深占位符和通配符。
受阅读文档启发的示例 - 所以您不必:
match point:
case (0,0):
print("Origin")
case (0,y):
print("Our current Y position is",y," now.")
您可以匹配任意嵌套的数据结构,包括占位符。在上面的例子中,我们匹配一个有两个项目的元组,在第二种情况下,我们使用一个占位符 y
,它在匹配时获得它的值。
您还可以以非常相似的方式匹配类属性:
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","units.")
这也解释了为什么您不能在 case 条件下匹配单个变量引用:您实际上并未匹配该变量的值,而是实际上引入了同名占位符!
因此,如果您要像这样打印 chosen_color
:
base_color = "red"
chosen_color = "green"
match chosen_color:
case base_color:
print("Our base color is",base_color)
它实际上会打印出来
我们的基色是绿色
因为 base_color
现在是一个占位符,它被分配了我们的 chosen_color
的值。
这种高级模式匹配还有更多用例,Python Docs 中提到了其中一些有趣的用例。
结语
Python 3.10 得到应有的采用需要时间。 Python 3.10.0 将于 2021 年 10 月 4 日稳定发布 - 这意味着它可能包含在 Ubuntu 22.04 及更高版本中。
如果您只是想自己玩玩和编写程序,将它们部署到您自己的服务器上,或者如果您打算以打包形式而不是纯源代码文件的形式分发您的作品,请尝试使用此新功能您的程序 - 这将是一个好处!
附录
尝试 Python 3.10.0
对于 Windows 和 MacOS 用户,this page 提供官方安装程序下载。
在 Debian 和 Ubuntu 上,您可以使用非常流行的“DeadSnakes”项目 PPA:
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.10
python3.10 --version
在不破坏系统的情况下尝试 Python 3.10.0
Docker 是一种使用 Python 3.10 的选项,无需任何复杂的设置步骤,并且在完全隔离的环境中。
docker run -it python:3.10.0a6-alpine
就是这样。随着时间的推移,可能会发布新的 alpha 或 beta 版本。然后,您需要将 a6
替换为 different version。
Python 3.10.0 之前的答案
没有,通常有两种方式,取决于代码上下文:
- 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")
- 字典查询:
另一种不太常见的方法是创建一个字典并在 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
)()
尽管不那么“pythonic”,但当在各种情况下您有大量降低可读性的代码时,这很有用。