剛剛,Python 3.10 正式釋出了!我發現了一個可怕的功能...

Python程式設計時光發表於2021-10-11

就在前幾天( 2021年10月4日) Python 終於正式釋出了 3.10 版本,看了下這個版本的一些特性,最受關注的應該就是 結構模式匹配 了吧?也就是大家所熟悉的 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 趕緊試用,可沒想到在我深入的體驗過後,我從最開始的期待,變成了敬畏。

敬畏,是因為這樣一個看似簡單的新功能,卻有著不少的學習成本,並且對 結構模式匹配 半知半解的人來說,會增大程式碼出錯的概率,並不是大數人都能輕鬆駕馭的。

我為什麼會這麼說呢?我會在文章最後來簡述我的觀點。

鑑於大多數人,都沒有實際用過這種 結構模式匹配,我會從 升級 3.10 開始教大家如何嘗鮮這個新功能,然後我會詳細的介紹 match-case 的使用方法。

1. 升級 3.10 新版本

我本機的電腦上目前的 Python 版本是 3.9.1 的

$ /usr/local/bin/python3 --version
Python 3.9.1

由於這邊我使用的是 mac,因此我從官網上下載的是 Python 3.10 的 pkg 檔案,如果是 win 的使用者,可以下載相應的 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 檔案,進入安裝流程

一路點選繼續,該同意的同意一下,出現如下提示表示安裝成功。

再次在終端上確認下是否升級成功

2. or 模式的使用

在上面我已經貼出一個 match-case 的最簡單示例,這邊就直接跳過簡單示例,來說說那些比較特殊的用法。

在 Python 3.10 中其實有新增一個 聯合型別操作符 | ,但這個只能用於型別,具體的用法,我會在下一篇文章中做詳細的介紹,本篇文章還是集中於 match-case 的使用。

在學習match-case 的時候,你會發現,也有一個類似於聯合型別操作符的用法,但請你要注意區別,它並不是聯合型別操作,而是在 match-case 下獨有的 or模式操作符 | ,它可以將多個具體相同邏輯的 case 語句簡寫成同一個

match status:
    case 401 | 403 | 404:
        print("Not allowed")
    case _:
        print("Something's wrong with the internet")

3. 萬用字元匹配任意物件

match-case 的出現有利於提高程式碼的可讀性,讓你的程式碼更加優雅,但同時要使用好它,也是有一些門檻的,特別是萬用字元的使用。

下邊我舉一些例子來進行講解

在如下程式碼中,使用了萬用字元 _ 和 可變引數中的 * 符號

import sys

match sys.argv[1:]:
    case ["quit"]:
        print("exit")
    case ["create", user]:     # 建立單個使用者
        print("create", user)
    case ["create", *users]:  # 批量建立多個使用者
        for user in users:
            print("create", user)
    case _:
        print("Sorry, I couldn't understand the argv")

最後一個 case 中的 _ 並不作為變數名,而表示一種特殊的模式,在前面的 case 中都未命中的情況下,該 case 會是最後的保障,能確保命中,它相當於 Go 語言中的 default 分支。

import "fmt"

func main() {
    education := "本科"

    switch education {
    case "博士":
        fmt.Println("我是博士")
    case "研究生":
        fmt.Println("我是研究生")
    case "本科":
        fmt.Println("我是本科生")
    case "大專":
        fmt.Println("我是大專生")
    default:
        fmt.Println("學歷未達標..")
    }
}

4. 使用可變引數 *args

第二個 case 和 第三個 case 非常的像,區別在於第三個 case中 users 前加了個 *,他跟原 Python 函式中的可變引數是一個用法,會匹配列表的多個值。

在該中表示可以從命令列引數中批量建立使用者。

在 match-case 中相應的 case 若有執行到,對應的變數是會被建立的。比如

5. 使用可變引數 **kv

在如下程式碼中,**rest 會匹配到所有的 args 中的 key 和 value

6. 長度的匹配方式

若你希望使用 case 僅對物件的長度做一些匹配,可以使用下面這樣的方式

  • [*_] 匹配任意長度的 list;
  • (_, _, *_) 匹配長度至少為 2 的 tuple

7. 類物件的匹配

對於類物件的匹配,下邊這個例子足夠簡單,不再講解。

8. 匹配要注意順序

在上邊基本介紹完了 match-case 的使用方法,如需更詳細的內容,不如去通讀下 pep 636 的內容。

在文章最開始的時候,我說過開發者應該對這些新特性 心存敬畏,match-case 這樣一個看似簡單的新功能,卻有著不少的學習成本,如果對 結構模式匹配 半知半解的人來說,可能會增大程式碼出錯的概率,並不是大數人都能輕鬆駕馭的。

之所以會這麼說,是因為 match-case 在面對不同的物件,它的匹配的規則也有所不同。

  • 當 match 的物件是一個 list 或者 tuple 的時候,需要長度和元素值都能匹配,才能命中,這就是為什麼下面這個例子走的是第三個 case 而不是第二個 case。

  • 當 match 的物件是一個 dict 的時候,規則卻有所不同,只要 case 表示式中的 key 在所 match 的物件中有存在,即可命中。

  • 而當 match 的物件是類物件時,匹配的規則是,跟 dict 有點類似,只要物件型別和物件的屬性有滿足 case 的條件,就能命中。

因此在寫 match-case 的時候,最大的難點可能就是如何把握這個順序,才能確保你寫的程式碼不會翻車。

我個人總結一些規律,僅供大家參考:

  • list 或者 tuple:應該從不格式到嚴格
  • dict 或者 object:應該從嚴格到不嚴格

在經過半天時間的嚐鮮後,我有了一些自己的理解,分享給大家,不知道我的理解有沒有問題,但我依然建議大家在 充分了解 match-case 的匹配規則 後,再去使用它。

另外,這個功能一出,有許多人表示 終於來了,也有一些人表示 太雞肋了

我對於此事的看法是,match-case 必然有一定的適用場景,但這不意味著 match-case 是必要的,所有的 match-case 都可以換成 if 表示式,但反過來卻不然,if 可以結合 and 和 or 承接 n 個多複雜的組合判斷,但 match-case 卻不行,它只能用於單個物件進行匹配判斷。

但是從一定程度上來說,它有點多餘,而且有一定的上手成本。

那麼對於這樣的一個 新特性,你會用它嗎?


文章最後給大家介紹三個我自己寫的線上文件:

第一個文件PyCharm 中文指南 1.0 文件

花了兩個多月的時間,整理了 100 個 PyCharm 的使用技巧,為了讓新手能夠直接上手,我花了很多的時間錄製了上百張 GIF 動圖,有興趣的前往線上文件閱讀。

第二個文件PyCharm 黑魔法指南 1.0 文件

系統收錄各種 Python 冷門知識,Python Shell 的多樣玩法,令人瘋狂的 Python 炫技操作,Python 的超詳細進階知識解讀,非常實用的 Python 開發技巧等。

第三個文件Python 中文指南 1.0 文件

花了三個月時間寫的一本 適合零基礎入門 Python 的全中文教程,搭配大量的程式碼案例,讓初學者對 程式碼的運作效果有一個直觀感受,教程既有深度又有廣度,每篇文章都會標內容的難度,是基礎還是進階的,可供讀者進行選擇,是一本難得的 Python 中文電子教程。

相關文章