阅读本文大概需要 10 分钟。

在这篇文章里,我们会聊一聊为什么 Python 决定不支持 switch 语句。

为什么想要聊这个话题呢?

主要是因为 switch 在其它语言中太常见了,而 Python 却不支持,这样的独特性本身就值得关注,而回答这个问题,也能更加看清 Python 在程序设计上的理念,了解 Python 在语法设计中的决策过程。

本文除了会详细分析 PEP-275 和 PEP-3103,还会介绍到 Python 最新的发展动态(PEP-622),即可能要引入的模式匹配(pattern matching)语法,相信这个话题会开阔大家的眼界,从而对 switch 语法有更为全面的认识。

1、switch 是什么?

在开始正题之前,我们需要先聊聊 switch 是什么?

有些同学可能会第一时间想到它……

喂~喂~,麻烦收收心,别总想着游戏啦,我们要说的是编程语言中的 switch 语句。

一般而言,switch 的语法格式如下:

switch(expression){case value1:// 语句break; // 可选case value2:// 语句break; // 可选default: // 可选// 语句
}

使用流程图来表示,大概是这样的:

它的用法不难理解:switch 语句的值满足哪一个 case 情况,就会执行对应的代码块,执行时遇到 break 就跳出,否则就继续执行下一个 case 分支;一般会在最后放一个 default 分支,作为兜底。

大多数语言都提供了 switch 语句或者极其相似的东西,例如,在 C/C++/Java /Go 等静态语言中,它们都支持 switch-case 结构;在 Ruby 中有类似的 case-when 结构,在 Shell 语言中,有相似的 case-in 结构,在 Perl 中,有 switch-case-else……

switch 语句的好处是支持“单条件多分支”的选择结构,相比 if-else 的二分选择结构,在某些时候会更为简洁清晰。

但是,在 Python 中,我们看不到 switch-case 或者相近的语法结构,这是为什么呢?

2、Python 为什么不支持 switch?

官方文档中有一篇 FAQ 包含了这个问题:Why isn’t there a switch or case statement in Python?

FAQ 即 Frequently Asked Questions 的缩写,表示常见问题,官方列了 27 个常见问题,完整清单在此:https://mp.weixin.qq.com/s/zabIvt4dfu_rf7SmGZXqXg

该文档给出了几个建议,告诉了我们几个 switch/case 的替代方案:

  • 使用 if-elif-else 条件判断语句

  • 使用字典,将 case 值与调用的函数映射起来

  • 使用内置 getattr() 检索特定的对象调用方法

曾有人提出过一些提案(即 PEP-275 和 PEP-3103),想给 Python 引入 switch 语法,然而,对于“是否以及如何进行靶场测试”,大家没有达成一致的共识。

靶场测试,即 range test,指的是对武器弹药的技术性能作各种测试验证,与药物的临床试验一样,都是在最终产品交付前的一项关键性测试。

官方文档对于“为什么 Python 不引入 switch”的解释,实际上来源于 Python 之父 Guido van Rossum 在 PEP-3103 中的意见:

出处:https://www.python.org/dev/peps/pep-3103

A quick poll during my keynote presentation at PyCon 2007 shows this proposal has no popular support. I therefore reject it.

我在 PyCon 2007 的主题演讲中做了一个快速的民意调查,结果表明这个提案没有得到广泛的支持。因此,我拒绝了它。

简而言之,PEP 提案有了,语法实现也有了雏形,但是核心开发者们似乎没有达成一致意见,最终导致提案流产了。

3、PEP-275 与 PEP-3103 说了什么?

PEP-3103 是在 2006 年提出的,PEP-275 则是在 2001 年提出的,它们的共同之处是提出了引入 switch 语句的某种必要性、分析了好几种备选的实现方案,然而,结局是都被拒绝了。

出处:https://www.python.org/dev/peps/pep-0275

那么,我们就先来回顾一下核心开发者们都做出了哪些讨论,看一看如果 Python 要实现 switch 结构,会是怎么样子的?(PS:PEP 里还涉及其它内容,本文只摘取与 switch 直接相关的部分)

PEP-275 提出的语法结构如下:

switch EXPR:case CONSTANT:SUITEcase CONSTANT:SUITE...else:SUITE

其中 else 分支是可选的,如果没有它,并且前面的分支都不满足的话,就什么也不做。另外 case 值 constant 支持不同类型,因为 expr 表达式的类型是动态的。

PEP-275 还提出让 switch 不支持掉落(fall-through)行为,即每个 case 分支相互独立而完整,不用像 C 语言那样需要写 break。

该 PEP 还列举了一些其它的 issue:

  • 重用现有关键字,不引入“switch”和“case”

  • 使用新的关键字,避免与 C 的 switch 概念混淆

  • 支持单分支多值选择(例如:case 'a', 'b', 'c': …)

  • 还有建议支持范围取值判断(例如:case 10..14: …)

除了首选方案,该 PEP 还记录了几种风格各异的语法方案:

case EXPR:of CONSTANT:SUITEof CONSTANT:SUITEelse:SUITEcase EXPR:if CONSTANT:SUITEif CONSTANT:SUITEelse:SUITEwhen EXPR:in CONSTANT_TUPLE:SUITEin CONSTANT_TUPLE:SUITE...
else:SUITE

PEP-275 记录下了不少重要的思路和问题,为 PEP-3103 的出现做了很好的铺垫。

那么,我们再来看看由 Guido 编写的 PEP-3103 说了些什么吧。

它首先认可了 PEP-275 中的两个基础设定,例如,实现“隐式的 break”,不让 case 分支出现 fall-through 这种转移控制权的情况(其它语言似乎都要求显式地写 break);else 分支是可选的,复用 else 关键字,而不用引入“default”。

对于 PEP-275 提倡的那种风格,Guido 比较认可,但也认为它的问题是缩进层次太多,因此建议减少代码分支缩进的空格数,例如本来缩进 4 空格,改为缩进 2 空格。

PEP-3103 还列举了另外三种实现方案,分析了它们的差异以及问题,具体内容从略,这里只给大家看看它们的风格:

# case 分支不缩进
switch EXPR:
case EXPR:SUITE
case EXPR:SUITE
....
else:SUITE# switch 语句后不加冒号
switch EXPR
case EXPR:SUITE
case EXPR:SUITE
....
else:SUITE# 省略 case 关键字
switch EXPR:EXPR:SUITEEXPR:SUITE...else:SUITE

在基础语法之外,Guido 花了很多篇幅来讨论扩展语法(Extended Syntax),即在一个 case 分支中实现匹配多个值的复杂情况:

case EXPR, EXPR, ...:# Guido 优选的
case in EXPR_LIST:case *EXPR:case [*]EXPR, [*]EXPR, ...:case *(EXPR, EXPR, ...):

他重点考虑到的问题包括:switch 中表达式的结果是元组或可迭代对象的情况、case 的值被看成元组解包的情况、在 case 分支作“*”星号操作……

接着,Guido 又用了非常非常多的篇幅来分析该如何实现 switch,其中讨论到的主要思路有:

  • 使用等价的 if-elif 链来定义 switch 语句(可能会做些优化)

  • 同上,另外所有表达式都必须是可哈希的(hashable)

  • 看作是预先计算的字典的分派(dispatch)

PEP 中这部分的内容非常多,因为在每个思路上,Guido 还考虑到了好几种实现路径,这导致了他在复杂分析后的结论是:It is too early to decide( 现在做决定为时尚早)。

阅读完 PEP-3103 后,我总体的感觉是:Guido 的思路非常发散、层次丰富,但是,缺少了他在面对其它问题时那“快刀斩乱麻”式的洞察力。

也就是说,在诸多的可能性方案中,他力求面面俱到,最终无法说服自己做出一个独裁的决定。阻力主要来自于他自己,而不是其他人。

不过,之所以会出现这种情况,也许跟他的预设立场有关:他似乎认为“Python is fine without a switch statement”,因此尽管写了很长的 PEP,但只是在把问题复杂化,把议题搁置起来。

最后,他在 PyCon 上做了一个小范围调查,借此“名正言顺”地拒绝了自己发起的 PEP,试图堵住众人的悠悠之口……

4、未来会有 switch 语句么?

归结起来,之所以 Python 没有 switch 语句,原因有:switch 的实现细节/功能点未经敲定、没有 switch 也挺好的、有其它不错的方法替代 switch、Guido 的小任性……

但是,我们还是要追问一句:未来会有 switch 语句么?或者类似的多分支选择结构?

为什么要有此一问呢?原因是有太多语言自带 switch 语句,而且也有很多人尝试编写提供 switch 功能的库(我记得在 PyCoder's Weekly 里曾见到过两次)。

我(Python猫)本人自始至终并不喜欢 switch,几乎可以肯定地说,Python 未来也不会有 switch,但是,它很可能会引入一个类似于 switch 且更为复杂的语法结构!

2020 年 6 月,PEP-622 被提出了,它建议引入在 Scala、Erlang 和 Rust 等语言中的模式匹配语法(pattern matching)。

截至 2020 年 10 月,该 PEP 已被分解成另外三个 PEP(634-636),目前都处于草案阶段。考虑到核心开发者们的参与情况以及话题讨论的情况,这些提案极有可能会在未来版本(比如正在开发中的 3.10)中实现。

以一个求平均数的函数为例,模式匹配语法可以实现成这样:

def average(*args):match args:case [x, y]:           # captures the two elements of a sequencereturn (x + y) / 2case [x]:              # captures the only element of a sequencereturn xcase []:return 0case x:                # captures the entire sequencereturn sum(x) / len(x)

match-case 结构神似于 switch-case 结构,然而它基于模式(pattern)而非表达式(expression),因此有更多待考虑的细节问题,也有更为广阔的应用空间。

对此话题感兴趣的读者,建议去查阅这几个新的 PEP。

最后,让我们回到标题中的问题:Python 为什么不支持 switch 语句?

官方文档的 FAQ 对此问题有一个解答,告诉我们有几个不错的替代写法,同时也留下了一条线索:曾有 PEP 提议引入 switch,只是没有成功实现。

沿着这条线索,本文拆解了 PEP-275 和 PEP-3103 这两篇文档,带大家看到了 Python 社区里提出过的风格各异的 switch 方案,以及诸多的悬而未决的问题。

最后,我们还关注到了最新的 PEP-622 的动态,看起来 switch 的“孪生兄弟” match 语法有望引入到 Python 中!switch 话题的讨论似乎要终止了,但是另一个更大的话题正在进行中!

推荐阅读

1

Linux!为何他一人就写出这么强的系统,中国却做不出来?

2

奇技淫巧:在 ssh 里面把服务器的文本复制到本地电脑

3

超全!我把 Python 的 200个标准库整理出来了

4‍‍

牛逼!GitHub 耗时整整一年开发的代码扫描工具终于上线了!

崔庆才

静觅博客博主,《Python3网络爬虫开发实战》作者

隐形字

个人公众号:进击的Coder

长按识别二维码关注

好文和朋友一起看~

Python 为什么不支持 switch 语句?相关推荐

  1. Python学习(13)--Lambda表达式和switch语句的实现

    1.Lambda表达式定义匿名函数    在Python中,Lambda表达式是用来快速定义一个最小函数,这个函数小到什么程度呢,小到只有一行代码,一条语句,在Python中有时候我们为了提高程序的可 ...

  2. python中常见的流程结构-Python分支结构(switch)操作简介

    Python当中并无switch语句,本文研究的主要是通过字典实现switch语句的功能,具体如下. switch语句用于编写多分支结构的程序,类似与if-.elif-.else语句. switch语 ...

  3. python 判断等于0_Python 条件语句介绍

    Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 可以通过下图来简单了解条件语句的执行过程: Python程序语言指定任何非0和非空(null)值为tr ...

  4. python之条件、循环语句

    其实,很多语言的语法都是相通的,包括初学python一样. 今天要说的是条件.循环语句.这部分也是相对比较简单的,就python而言,只是书写方式稍作改动罢了. 1.条件语句 (1)格式: if 判断 ...

  5. Python学习2 条件判断语句if,循环语句for while

    顺序,分支,循环结构 条件判断语句if 1)if-else- 2) if-elif-else 注意: 1)python中不支持switch-case语句 2)注意缩进! 3)区间范围内允许连续比较: ...

  6. 通俗易懂,Python的条件和循环语句

    条件控制 简单来说:当判断的条件为真是,执行某种代码逻辑,这就是条件控制. 那么在讲条件控制之前,可以给大家讲一个程序员当中流传的比较真实的一个例子 说有一天一个程序员,他的媳妇让他去出去买两个包子, ...

  7. delphi switch语句例子_Python系列之常用语句

    之前介绍了基本函数知识,这次我们一起来看下常用的语句,常用语句大概分为条件语句,循环语句,循环控制语句,pass语句这几种,我们一一来看: 1.条件语句 说起条件语句,我想学过编程的人会想到if-el ...

  8. Python中如何优雅地使用switch语句

    文章目录 Python中如何优雅地使用switch语句 案例一(简单情况) 案例二(带条件判断) 版权声明:本文为博主原创文章,转载请注明原文出处! 写作时间:2019-03-07 13:49:45 ...

  9. python进阶:switch语句、推导式与None类型

    一.python实现switch语句 简单示例 适合一般情形的示例 二.推导式:由已知对象推出另一对象 列表推导式 列表推导式内一般不涉及函数(匿名函数),因为其本身就自带函数的特性 map可以是替代 ...

最新文章

  1. Linux bridge 资料链接
  2. javascript中Date对象及方法
  3. NUS 联合 Sea AI Lab 发表 Multi-view Pose Transformer,完全端到端学习,超强可扩展性...
  4. 不得不学的http协议
  5. c语言自动插桩,静态插桩的方式来实现Hook Method
  6. 深度解析,抖音对口型唱歌类短视频内容制作流程,步骤技巧分享
  7. 用Java实现家庭收支记账软件
  8. Redis——SDS
  9. 导航栏菜单实现鼠标移入移出中英文切换的两种方法(css3和jQuery)
  10. percentile_approx函数用法
  11. jmete-jp@gc - Throughput Shaping Timer的使用
  12. Elasticsearch数据读写过程
  13. 漫画插画绘图工具:MediBangPaintPro for Mac
  14. 猎头职场:真正城府深的人都不会做这些
  15. MTK平台的LCM防静电(esd-check)机制
  16. 51单片机 Proteus仿真 智能窗帘
  17. 10 个最好的免费开源网店系统
  18. ChipGAN: A Generative Adversarial Network for Chinese Ink Wash Painting Style Transfer翻译
  19. python3爬虫爬取百度贴吧下载图片
  20. JEECMS --Java CMs内容管理系统

热门文章

  1. Android开发实现上一页,下一页显示内容
  2. c++在文件中提取数字或字母
  3. HDU 5804/BC 86A Price List
  4. Java web学习文档
  5. 考驾照--驾驶证考试
  6. GPG对称加密与非对称加密
  7. h5活动是什么意思_浅谈什么是H5页面,怎么制作h5页面
  8. 智慧运维解决方案-最新全套文件
  9. CPU占用过高问题的排查及解决
  10. 调试MCP2515驱动时遇到的问题 CAN控制器和CAN收发器之间的TX和RX引脚接反,导致无法正常收发数据