自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Python 為什么不支持 switch 語(yǔ)句?

開(kāi)發(fā) 后端
主要是因?yàn)?switch 在其它語(yǔ)言中太常見(jiàn)了,而 Python 卻不支持,這樣的獨(dú)特性本身就值得關(guān)注,而回答這個(gè)問(wèn)題,也能更加看清 Python 在程序設(shè)計(jì)上的理念,了解 Python 在語(yǔ)法設(shè)計(jì)中的決策過(guò)程。

[[345017]]

在這篇文章里,我們會(huì)聊一聊為什么 Python 決定不支持 switch 語(yǔ)句。

為什么想要聊這個(gè)話題呢?

主要是因?yàn)?switch 在其它語(yǔ)言中太常見(jiàn)了,而 Python 卻不支持,這樣的獨(dú)特性本身就值得關(guān)注,而回答這個(gè)問(wèn)題,也能更加看清 Python 在程序設(shè)計(jì)上的理念,了解 Python 在語(yǔ)法設(shè)計(jì)中的決策過(guò)程。

本文除了會(huì)詳細(xì)分析 PEP-275 和 PEP-3103,還會(huì)介紹到 Python 最新的發(fā)展動(dòng)態(tài)(PEP-622),即可能要引入的模式匹配(pattern matching)語(yǔ)法,相信這個(gè)話題會(huì)開(kāi)闊大家的眼界,從而對(duì) switch 語(yǔ)法有更為全面的認(rèn)識(shí)。

1、switch 是什么?

在開(kāi)始正題之前,我們需要先聊聊 switch 是什么?

有些同學(xué)可能會(huì)第一時(shí)間想到它……

[[345018]]

 

喂~喂~,麻煩收收心,別總想著游戲啦,我們要說(shuō)的是編程語(yǔ)言中的 switch 語(yǔ)句。

一般而言,switch 的語(yǔ)法格式如下:

  1. switch(expression){ 
  2.     case value1: 
  3.        // 語(yǔ)句 
  4.        break; // 可選 
  5.     case value2: 
  6.        // 語(yǔ)句 
  7.        break; // 可選 
  8.     default: // 可選 
  9.        // 語(yǔ)句 

使用流程圖來(lái)表示,大概是這樣的:

 

它的用法不難理解:switch 語(yǔ)句的值滿足哪一個(gè) case 情況,就會(huì)執(zhí)行對(duì)應(yīng)的代碼塊,執(zhí)行時(shí)遇到 break 就跳出,否則就繼續(xù)執(zhí)行下一個(gè) case 分支;一般會(huì)在最后放一個(gè) default 分支,作為兜底。

大多數(shù)語(yǔ)言都提供了 switch 語(yǔ)句或者極其相似的東西,例如,在 C/C++/Java /Go 等靜態(tài)語(yǔ)言中,它們都支持 switch-case 結(jié)構(gòu);在 Ruby 中有類似的 case-when 結(jié)構(gòu),在 Shell 語(yǔ)言中,有相似的 case-in 結(jié)構(gòu),在 Perl 中,有 switch-case-else……

switch 語(yǔ)句的好處是支持“單條件多分支”的選擇結(jié)構(gòu),相比 if-else 的二分選擇結(jié)構(gòu),在某些時(shí)候會(huì)更為簡(jiǎn)潔清晰。

但是,在 Python 中,我們看不到 switch-case 或者相近的語(yǔ)法結(jié)構(gòu),這是為什么呢?

2、Python 為什么不支持 switch?

官方文檔中有一篇 FAQ 包含了這個(gè)問(wèn)題:Why isn’t there a switch or case statement in Python?

 

FAQ 即 Frequently Asked Questions 的縮寫(xiě),表示常見(jiàn)問(wèn)題,官方列了 27 個(gè)常見(jiàn)問(wèn)題,完整清單在此:https://mp.weixin.qq.com/s/zabIvt4dfu_rf7SmGZXqXg

該文檔給出了幾個(gè)建議,告訴了我們幾個(gè) switch/case 的替代方案:

  • 使用 if-elif-else 條件判斷語(yǔ)句
  • 使用字典,將 case 值與調(diào)用的函數(shù)映射起來(lái)
  • 使用內(nèi)置 getattr() 檢索特定的對(duì)象調(diào)用方法

曾有人提出過(guò)一些提案(即 PEP-275 和 PEP-3103),想給 Python 引入 switch 語(yǔ)法,然而,對(duì)于“是否以及如何進(jìn)行靶場(chǎng)測(cè)試”,大家沒(méi)有達(dá)成一致的共識(shí)。

靶場(chǎng)測(cè)試,即 range test,指的是對(duì)武器彈藥的技術(shù)性能作各種測(cè)試驗(yàn)證,與藥物的臨床試驗(yàn)一樣,都是在最終產(chǎn)品交付前的一項(xiàng)關(guān)鍵性測(cè)試。

官方文檔對(duì)于“為什么 Python 不引入 switch”的解釋,實(shí)際上來(lái)源于 Python 之父 Guido van Rossum 在 PEP-3103 中的意見(jiàn):

出處: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 的主題演講中做了一個(gè)快速的民意調(diào)查,結(jié)果表明這個(gè)提案沒(méi)有得到廣泛的支持。因此,我拒絕了它。

簡(jiǎn)而言之,PEP 提案有了,語(yǔ)法實(shí)現(xiàn)也有了雛形,但是核心開(kāi)發(fā)者們似乎沒(méi)有達(dá)成一致意見(jiàn),最終導(dǎo)致提案流產(chǎn)了。

3、PEP-275 與 PEP-3103 說(shuō)了什么?

PEP-3103 是在 2006 年提出的,PEP-275 則是在 2001 年提出的,它們的共同之處是提出了引入 switch 語(yǔ)句的某種必要性、分析了好幾種備選的實(shí)現(xiàn)方案,然而,結(jié)局是都被拒絕了。

 

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

那么,我們就先來(lái)回顧一下核心開(kāi)發(fā)者們都做出了哪些討論,看一看如果 Python 要實(shí)現(xiàn) switch 結(jié)構(gòu),會(huì)是怎么樣子的?(PS:PEP 里還涉及其它內(nèi)容,本文只摘取與 switch 直接相關(guān)的部分)

PEP-275 提出的語(yǔ)法結(jié)構(gòu)如下:

  1. switch EXPR: 
  2.     case CONSTANT: 
  3.         SUITE 
  4.     case CONSTANT: 
  5.         SUITE 
  6.     ... 
  7.     else
  8.         SUITE 

其中 else 分支是可選的,如果沒(méi)有它,并且前面的分支都不滿足的話,就什么也不做。另外 case 值 constant 支持不同類型,因?yàn)?expr 表達(dá)式的類型是動(dòng)態(tài)的。

PEP-275 還提出讓 switch 不支持掉落(fall-through)行為,即每個(gè) case 分支相互獨(dú)立而完整,不用像 C 語(yǔ)言那樣需要寫(xiě) break。

該 PEP 還列舉了一些其它的 issue:

  • 重用現(xiàn)有關(guān)鍵字,不引入“switch”和“case”
  • 使用新的關(guān)鍵字,避免與 C 的 switch 概念混淆
  • 支持單分支多值選擇(例如:case 'a', 'b', 'c': …)
  • 還有建議支持范圍取值判斷(例如:case 10..14: …)

除了首選方案,該 PEP 還記錄了幾種風(fēng)格各異的語(yǔ)法方案:

  1. case EXPR: 
  2.     of CONSTANT: 
  3.         SUITE 
  4.     of CONSTANT: 
  5.         SUITE 
  6.     else
  7.         SUITE 
  8.  
  9. case EXPR: 
  10.     if CONSTANT: 
  11.          SUITE 
  12.     if CONSTANT: 
  13.         SUITE 
  14.     else
  15.         SUITE 
  16.  
  17. when EXPR: 
  18.     in CONSTANT_TUPLE: 
  19.         SUITE 
  20.     in CONSTANT_TUPLE: 
  21.         SUITE 
  22.     ... 
  23. else
  24.      SUITE 

PEP-275 記錄下了不少重要的思路和問(wèn)題,為 PEP-3103 的出現(xiàn)做了很好的鋪墊。

那么,我們?cè)賮?lái)看看由 Guido 編寫(xiě)的 PEP-3103 說(shuō)了些什么吧。

它首先認(rèn)可了 PEP-275 中的兩個(gè)基礎(chǔ)設(shè)定,例如,實(shí)現(xiàn)“隱式的 break”,不讓 case 分支出現(xiàn) fall-through 這種轉(zhuǎn)移控制權(quán)的情況(其它語(yǔ)言似乎都要求顯式地寫(xiě) break);else 分支是可選的,復(fù)用 else 關(guān)鍵字,而不用引入“default”。

對(duì)于 PEP-275 提倡的那種風(fēng)格,Guido 比較認(rèn)可,但也認(rèn)為它的問(wèn)題是縮進(jìn)層次太多,因此建議減少代碼分支縮進(jìn)的空格數(shù),例如本來(lái)縮進(jìn) 4 空格,改為縮進(jìn) 2 空格。

PEP-3103 還列舉了另外三種實(shí)現(xiàn)方案,分析了它們的差異以及問(wèn)題,具體內(nèi)容從略,這里只給大家看看它們的風(fēng)格:

  1. case 分支不縮進(jìn) 
  2. switch EXPR: 
  3. case EXPR: 
  4.     SUITE 
  5. case EXPR: 
  6.     SUITE 
  7. .... 
  8. else
  9.     SUITE 
  10.  
  11. # switch 語(yǔ)句后不加冒號(hào) 
  12. switch EXPR 
  13. case EXPR: 
  14.     SUITE 
  15. case EXPR: 
  16.     SUITE 
  17. .... 
  18. else
  19.     SUITE 
  20.  
  21. # 省略 case 關(guān)鍵字 
  22. switch EXPR: 
  23.     EXPR: 
  24.         SUITE 
  25.     EXPR: 
  26.         SUITE 
  27.     ... 
  28.     else
  29.         SUITE 

在基礎(chǔ)語(yǔ)法之外,Guido 花了很多篇幅來(lái)討論擴(kuò)展語(yǔ)法(Extended Syntax),即在一個(gè) case 分支中實(shí)現(xiàn)匹配多個(gè)值的復(fù)雜情況:

  1. case EXPR, EXPR, ...: 
  2.  
  3. # Guido 優(yōu)選的 
  4. case in EXPR_LIST: 
  5.  
  6. case *EXPR: 
  7.  
  8. case [*]EXPR, [*]EXPR, ...: 
  9.  
  10. case *(EXPR, EXPR, ...): 

他重點(diǎn)考慮到的問(wèn)題包括:switch 中表達(dá)式的結(jié)果是元組或可迭代對(duì)象的情況、case 的值被看成元組解包的情況、在 case 分支作“*”星號(hào)操作……

接著,Guido 又用了非常非常多的篇幅來(lái)分析該如何實(shí)現(xiàn) switch,其中討論到的主要思路有:

  • 使用等價(jià)的 if-elif 鏈來(lái)定義 switch 語(yǔ)句(可能會(huì)做些優(yōu)化)
  • 同上,另外所有表達(dá)式都必須是可哈希的(hashable)
  • 看作是預(yù)先計(jì)算的字典的分派(dispatch)

PEP 中這部分的內(nèi)容非常多,因?yàn)樵诿總€(gè)思路上,Guido 還考慮到了好幾種實(shí)現(xiàn)路徑,這導(dǎo)致了他在復(fù)雜分析后的結(jié)論是:It is too early to decide( 現(xiàn)在做決定為時(shí)尚早)。

閱讀完 PEP-3103 后,我總體的感覺(jué)是:Guido 的思路非常發(fā)散、層次豐富,但是,缺少了他在面對(duì)其它問(wèn)題時(shí)那“快刀斬亂麻”式的洞察力。

也就是說(shuō),在諸多的可能性方案中,他力求面面俱到,最終無(wú)法說(shuō)服自己做出一個(gè)獨(dú)裁的決定。阻力主要來(lái)自于他自己,而不是其他人。

不過(guò),之所以會(huì)出現(xiàn)這種情況,也許跟他的預(yù)設(shè)立場(chǎng)有關(guān):他似乎認(rèn)為“Python is fine without a switch statement”,因此盡管寫(xiě)了很長(zhǎng)的 PEP,但只是在把問(wèn)題復(fù)雜化,把議題擱置起來(lái)。

最后,他在 PyCon 上做了一個(gè)小范圍調(diào)查,借此“名正言順”地拒絕了自己發(fā)起的 PEP,試圖堵住眾人的悠悠之口……

4、未來(lái)會(huì)有 switch 語(yǔ)句么?

歸結(jié)起來(lái),之所以 Python 沒(méi)有 switch 語(yǔ)句,原因有:switch 的實(shí)現(xiàn)細(xì)節(jié)/功能點(diǎn)未經(jīng)敲定、沒(méi)有 switch 也挺好的、有其它不錯(cuò)的方法替代 switch、Guido 的小任性……

但是,我們還是要追問(wèn)一句:未來(lái)會(huì)有 switch 語(yǔ)句么?或者類似的多分支選擇結(jié)構(gòu)?

為什么要有此一問(wèn)呢?原因是有太多語(yǔ)言自帶 switch 語(yǔ)句,而且也有很多人嘗試編寫(xiě)提供 switch 功能的庫(kù)(我記得在 PyCoder's Weekly 里曾見(jiàn)到過(guò)兩次)。

我(Python貓)本人自始至終并不喜歡 switch,幾乎可以肯定地說(shuō),Python 未來(lái)也不會(huì)有 switch,但是,它很可能會(huì)引入一個(gè)類似于 switch 且更為復(fù)雜的語(yǔ)法結(jié)構(gòu)!

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

 

截至 2020 年 10 月,該 PEP 已被分解成另外三個(gè) PEP(634-636),目前都處于草案階段??紤]到核心開(kāi)發(fā)者們的參與情況以及話題討論的情況,這些提案極有可能會(huì)在未來(lái)版本(比如正在開(kāi)發(fā)中的 3.10)中實(shí)現(xiàn)。

以一個(gè)求平均數(shù)的函數(shù)為例,模式匹配語(yǔ)法可以實(shí)現(xiàn)成這樣:

  1. def average(*args): 
  2.     match args: 
  3.         case [x, y]:           # captures the two elements of a sequence 
  4.             return (x + y) / 2 
  5.         case [x]:              # captures the only element of a sequence 
  6.             return x 
  7.         case []: 
  8.             return 0 
  9.         case x:                # captures the entire sequence 
  10.             return sum(x) / len(x) 

match-case 結(jié)構(gòu)神似于 switch-case 結(jié)構(gòu),然而它基于模式(pattern)而非表達(dá)式(expression),因此有更多待考慮的細(xì)節(jié)問(wèn)題,也有更為廣闊的應(yīng)用空間。

對(duì)此話題感興趣的讀者,建議去查閱這幾個(gè)新的 PEP。

最后,讓我們回到標(biāo)題中的問(wèn)題:Python 為什么不支持 switch 語(yǔ)句?

官方文檔的 FAQ 對(duì)此問(wèn)題有一個(gè)解答,告訴我們有幾個(gè)不錯(cuò)的替代寫(xiě)法,同時(shí)也留下了一條線索:曾有 PEP 提議引入 switch,只是沒(méi)有成功實(shí)現(xiàn)。

沿著這條線索,本文拆解了 PEP-275 和 PEP-3103 這兩篇文檔,帶大家看到了 Python 社區(qū)里提出過(guò)的風(fēng)格各異的 switch 方案,以及諸多的懸而未決的問(wèn)題。

 

最后,我們還關(guān)注到了最新的 PEP-622 的動(dòng)態(tài),看起來(lái) switch 的“孿生兄弟” match 語(yǔ)法有望引入到 Python 中!switch 話題的討論似乎要終止了,但是另一個(gè)更大的話題正在進(jìn)行中!

作者簡(jiǎn)介 

豌豆花下貓,生于廣東畢業(yè)于武大,現(xiàn)為蘇漂程序員,有一些極客思維,也有一些人文情懷,有一些溫度,還有一些態(tài)度。

本文轉(zhuǎn)載自微信公眾號(hào)「Python貓」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Python貓公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: Python貓
相關(guān)推薦

2021-02-01 13:53:53

StringlongJava

2020-07-22 08:01:41

Python開(kāi)發(fā)運(yùn)算符

2021-01-22 15:31:47

JavaSwitchString

2021-10-27 07:15:36

Go 循環(huán)引用

2021-04-20 19:23:07

語(yǔ)法switch-casePython

2021-08-02 09:31:20

Python工具代碼

2021-12-09 10:51:47

Go繼承

2021-12-15 07:49:22

Go語(yǔ)言設(shè)計(jì)

2024-01-01 08:10:40

Go語(yǔ)言map

2024-01-05 08:45:35

Go語(yǔ)言map

2024-05-28 08:55:52

2023-01-28 08:05:32

轉(zhuǎn)換Go泛型

2021-07-13 08:09:34

微博推特評(píng)論

2009-03-12 08:42:38

AndroidWMMTK

2021-11-08 11:02:01

Go函數(shù)重載

2021-06-11 00:03:31

鴻蒙智能手機(jī)

2014-06-05 15:16:49

Linux開(kāi)源Flash

2024-03-08 08:51:59

Gomain函數(shù)

2009-03-11 17:32:22

聯(lián)發(fā)科WMAndroid

2022-05-09 10:28:42

SnapsUbuntuFlatpak
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)