Python 3.10 正式發(fā)布了!新功能match-case嘗鮮介紹~

來源 |?Python編程時光
就在前幾天( 2021年10月4日) Python 終于正式發(fā)布了 3.10 版本,看了下這個版本的一些特性,最受關(guān)注的應(yīng)該就是 結(jié)構(gòu)模式匹配 了吧?也就是大家所熟悉的switch-case,寫錯了不好意思,是 match-case。

下邊是最簡單的一個 match-case 的例子,看起來是不是非常的直觀簡潔?
def?http_error(status):
????match?status:
????????case?400:
????????????print("Bad?request")
????????case?404:
????????????print("Not?found")
????????case?418:
????????????print("I'm?a?teapot")
????????case?_:
????????????print("Something's?wrong?with?the?internet")
對這個功能滿懷期待的我,趕緊就下載升級了 3.10 的 Python 趕緊試用,可沒想到在我深入的體驗(yàn)過后,我從最開始的期待,變成了敬畏。
敬畏,是因?yàn)檫@樣一個看似簡單的新功能,卻有著不少的學(xué)習(xí)成本,并且對 結(jié)構(gòu)模式匹配 半知半解的人來說,會增大代碼出錯的概率,并不是大數(shù)人都能輕松駕馭的。
我為什么會這么說呢?我會在文章最后來簡述我的觀點(diǎn)。
鑒于大多數(shù)人,都沒有實(shí)際用過這種 結(jié)構(gòu)模式匹配,我會從 升級 3.10 開始教大家如何嘗鮮這個新功能,然后我會詳細(xì)的介紹 match-case 的使用方法。
?1. 升級 3.10 新版本
我本機(jī)的電腦上目前的 Python 版本是 3.9.1 的
$?/usr/local/bin/python3?--version
Python?3.9.1
由于這邊我使用的是 mac,因此我從官網(wǎng)上下載的是 Python 3.10 的 pkg 文件,如果是 win 的用戶,可以下載相應(yīng)的 msi 或者 exe 文件。
下載鏈接我貼在下邊,可以直接訪問下載
mac:?https://www.python.org/ftp/python/3.10.0/python-3.10.0-macos11.pkg
win:?https://www.python.org/ftp/python/3.10.0/python-3.10.0-amd64.exe
我下載好安裝文件后,雙擊安裝,之后就雙擊下載的 pkg 文件,進(jìn)入安裝流程

一路點(diǎn)擊繼續(xù),該同意的同意一下,出現(xiàn)如下提示表示安裝成功。

再次在終端上確認(rèn)下是否升級成功

?2. or 模式的使用
在上面我已經(jīng)貼出一個 match-case 的最簡單示例,這邊就直接跳過簡單示例,來說說那些比較特殊的用法。
在 Python 3.10 中其實(shí)有新增一個 聯(lián)合類型操作符 | ,但這個只能用于類型,具體的用法,我會在下一篇文章中做詳細(xì)的介紹,本篇文章還是集中于 match-case 的使用。
在學(xué)習(xí)match-case 的時候,你會發(fā)現(xiàn),也有一個類似于聯(lián)合類型操作符的用法,但請你要注意區(qū)別,它并不是聯(lián)合類型操作,而是在 match-case 下獨(dú)有的 or模式操作符 | ,它可以將多個具體相同邏輯的 case 語句簡寫成同一個
match?status:
????case?401?|?403?|?404:
????????print("Not?allowed")
????case?_:
????????print("Something's?wrong?with?the?internet")
?3. 通配符匹配任意對象
match-case 的出現(xiàn)有利于提高代碼的可讀性,讓你的代碼更加優(yōu)雅,但同時要使用好它,也是有一些門檻的,特別是通配符的使用。
下邊我舉一些例子來進(jìn)行講解
在如下代碼中,使用了通配符 _ 和 可變參數(shù)中的 ?* 符號
import?sys
match?sys.argv[1:]:
????case?["quit"]:
????????print("exit")
????case?["create",?user]:?????#?創(chuàng)建單個用戶
????????print("create",?user)
????case?["create",?*users]:??#?批量創(chuàng)建多個用戶
????????for?user?in?users:
????????????print("create",?user)
????case?_:
????????print("Sorry,?I?couldn't?understand?the?argv")
最后一個 case 中的 _ 并不作為變量名,而表示一種特殊的模式,在前面的 case 中都未命中的情況下,該 case 會是最后的保障,能確保命中,它相當(dāng)于 Go 語言中的 default 分支。
import?"fmt"
func?main()?{
????education?:=?"本科"
????switch?education?{
????case?"博士":
????????fmt.Println("我是博士")
????case?"研究生":
????????fmt.Println("我是研究生")
????case?"本科":
????????fmt.Println("我是本科生")
????case?"大專":
????????fmt.Println("我是大專生")
????default:
????????fmt.Println("學(xué)歷未達(dá)標(biāo)..")
????}
}
?4. 使用可變參數(shù) *args
第二個 case 和 第三個 case 非常的像,區(qū)別在于第三個 case中 users 前加了個 *,他跟原 Python 函數(shù)中的可變參數(shù)是一個用法,會匹配列表的多個值。
在該中表示可以從命令行參數(shù)中批量創(chuàng)建用戶。

在 match-case 中相應(yīng)的 case 若有運(yùn)行到,對應(yīng)的變量是會被創(chuàng)建的。比如

?5. 使用可變參數(shù) **kv
在如下代碼中,**rest 會匹配到所有的 args 中的 key 和 value

?6. 長度的匹配方式
若你希望使用 case 僅對對象的長度做一些匹配,可以使用下面這樣的方式
[*_]匹配任意長度的list;(, , *_)匹配長度至少為 2 的tuple。
?7. 類對象的匹配
對于類對象的匹配,下邊這個例子足夠簡單,不再講解。

?8. 匹配要注意順序
在上邊基本介紹完了 match-case 的使用方法,如需更詳細(xì)的內(nèi)容,不如去通讀下 PEP?636(https://www.python.org/dev/peps/pep-0636/)?的內(nèi)容。
在文章最開始的時候,我說過開發(fā)者應(yīng)該對這些新特性 心存敬畏,match-case 這樣一個看似簡單的新功能,卻有著不少的學(xué)習(xí)成本,如果對 結(jié)構(gòu)模式匹配 半知半解的人來說,可能會增大代碼出錯的概率,并不是大數(shù)人都能輕松駕馭的。
之所以會這么說,是因?yàn)?match-case 在面對不同的對象,它的匹配的規(guī)則也有所不同。
當(dāng) match 的對象是一個 list 或者 tuple 的時候,需要長度和元素值都能匹配,才能命中,這就是為什么下面這個例子走的是第三個 case 而不是第二個 case。

當(dāng) match 的對象是一個 dict 的時候,規(guī)則卻有所不同,只要 case 表達(dá)式中的 key 在所 match 的對象中有存在,即可命中。

而當(dāng) match 的對象是類對象時,匹配的規(guī)則是,跟 dict 有點(diǎn)類似,只要對象類型和對象的屬性有滿足 case 的條件,就能命中。

因此在寫 match-case 的時候,最大的難點(diǎn)可能就是如何把握這個順序,才能確保你寫的代碼不會翻車。
我個人總結(jié)一些規(guī)律,僅供大家參考:
list 或者 tuple:應(yīng)該從不格式到嚴(yán)格
dict 或者 object:應(yīng)該從嚴(yán)格到不嚴(yán)格
在經(jīng)過半天時間的嘗鮮后,我有了一些自己的理解,分享給大家,不知道我的理解有沒有問題,但我依然建議大家在 充分了解 match-case 的匹配規(guī)則 后,再去使用它。

更多教程,關(guān)注豬哥??
