當前位置: 妍妍網 > 碼農

Python 3.8 新運算子 := 讓我們懶出新高度

2024-04-24碼農

背景

Python 的語法風格確實是懶人福音,真是做到了多寫一行都是罪。就拿 Python-3.8 版本來說吧,為了少寫一行程式碼,直接搞出了一個新的運算子 ` := `。

先給結論!這個運算子不是必要的。也就是說沒有它我們也能寫程式,只是有了它之後我們的程式碼可以更加簡潔。

下面我就來說一下這個運算子的故事!

階段 一

這個階段大家做事都中規中矩,程式碼上直抒胸臆。給個例子吧。假設我們有一個函式,它是用來處理列表的,它會在處理之前檢查一下列表的長度,當長度大於 7 時直接結束。階段一這個時候的程式碼看起來如下。

deffun(lst=None):""" Parameters: lst: 列表 Return: None """# if len(lst) > 7: print(f"len(lst) = {len(lst)} gt 7 , not supported .")return# 其它邏輯

這裏有一個小小的問題, 就是 `len(lst)` 在命中 if 的語句時候它還會在 print 語句裏面再被計算一次 。如果計算本身的開銷就比較高,少計算一次就非常有吸重力了,階段二就是向這個方向前進演化的。

階段二

階段二的寫法也是非常直接,只要保存一下第一次計算的結果,第二次的時候直接取結果,這樣就不用再計算一次了。上程式碼

deffun(lst=None):""" Parameters: lst: 列表 Return: None """# n = len(lst)if n > 7: print(f"len(lst) = {n} gt 7 , not supported .")return# 其它邏輯

階段二的寫法也不是完全沒有可以改進的地方, 我們看 n 其實只在 if 塊裏面有用到,但是它的聲明位置是在 if 之外的。這個就給人一種,這個 n 非常重要後面的程式碼還會用到它的感覺。也就是說這種寫法沒有辦法表現出 n 就是一個臨時變量

好在這種語意已經可以在 Python-3.8 這個版本中表達了,不過我們要借助全新的運算子 ` := ` 來實作。 詳細的請看階段三。

階段三

階段三是真正的做到了形與意合,並且沒有什麽學習成本,語法上可以說是一看就懂,我直接上程式碼。

deffun(lst=None):""" Parameters: lst: 列表 Return: None """# if (n:= len(lst)) > 7: print(f"len(lst) = {n} gt 7 , not supported .")return# 其它邏輯

現在從詞法上看,就能非常明確地知道 n 只在 if 語句內起作用。由於階段三只是階段二的語法糖,也就是說從作用域上來講 n 在 if 語句之後還是可以正常存取,這個應該就是唯一美中不足的地方了吧。

為什麽說 := 是語法糖

這一點是從官方文件上不能直接看出來的,需要我們去看 fun 函式兩種不同寫法,編譯出來的字節碼。

In[1]: import disIn[2]: def fun(lst=None):...: """...: Parameters:...: lst: 列表...: ...: Return:...: None...: """...: # ...: ...: if (n:= len(lst)) > 7:...: print(f"len(lst) = {n} gt 7 , not supported .")...: return...: In[3]: dis.dis(fun)10 RESUME 0112 LOAD_GLOBAL 1 (NULL + len)14LOAD_FAST 0 (lst)16PRECALL 120CALL 130COPY 132STORE_FAST 1 (n)34LOAD_CONST 1 (7)36COMPARE_OP 4 (>)42POP_JUMP_FORWARD_IF_FALSE 21 (to 86)1244 LOAD_GLOBAL 3 (NULL + print)56LOAD_CONST 2 ('len(lst) = ')58LOAD_FAST 1 (n)60FORMAT_VALUE 062LOAD_CONST 3 (' gt 7 , not supported .')64BUILD_STRING 366PRECALL 170CALL 180POP_TOP1382 LOAD_CONST 4 (None)84RETURN_VALUE11>> 86 LOAD_CONST 4 (None)88RETURN_VALUEIn[4]: def fun(lst=None):...: """...: Parameters:...: lst: 列表...: ...: Return:...: None...: """...: # ...: n = len(lst)...: if n > 7:...: print(f"len(lst) = {n} gt 7 , not supported .")...: return...: In[5]: dis.dis(fun)10 RESUME 0102 LOAD_GLOBAL 1 (NULL + len)14LOAD_FAST 0 (lst)16PRECALL 120CALL 130STORE_FAST 1 (n)1132 LOAD_FAST 1 (n)34LOAD_CONST 1 (7)36COMPARE_OP 4 (>)42POP_JUMP_FORWARD_IF_FALSE 21 (to 86)1244 LOAD_GLOBAL 3 (NULL + print)56LOAD_CONST 2 ('len(lst) = ')58LOAD_FAST 1 (n)60FORMAT_VALUE 062LOAD_CONST 3 (' gt 7 , not supported .')64BUILD_STRING 366PRECALL 170CALL 180POP_TOP1382 LOAD_CONST 4 (None)84RETURN_VALUE11>> 86 LOAD_CONST 4 (None)88RETURN_VALUE

可以看到階段三和階段二的字節碼是一模一樣的。

以上是今天的分享,最後推薦一下我的【Python潮流周刊】專欄。試執行付費模式,目前最低價,即將漲價!歡迎訂閱。