Python 3.10 中新的功能和變化

東方天宇發表於2021-04-28

隨著最後一個alpha版釋出,Python 3.10 的功能更改全面敲定!

現在,正是體驗Python 3.10 新功能的理想時間!正如標題所言,本文將給大家分享Python 3.10中所有重要的功能和更改。

新功能1:聯合運算子

在過去, |符號用於 "算術或"運算,例如:

print(0 | 0)
print(0 | 1)
print({1, 2} | {2, 3})

輸出:

0
1
{1, 2, 3}

在Python 3.10中, | 符號有的新語法,可以表示x型別 或 Y型別,以取代之前的typing.Union 完成型別註解

舉個例子:

函式的引數應該是一個int 或 str型別

舊的寫法:

  • from typing import Union
    
    
    def f(value: Union[int, str]) -> Union[int, str]:
        return value*2
    

新的寫法:

  • def f(value: int | str) -> int | str:
        return value*2
    

這種新的語法也被作為isinstance()issubclass() 的第二個引數,用於型別判斷

 isinstance(1086, int | str)   # 10086是否為 int型 或 str型

新功能2: 多行上下文管理器

在過去,上下文管理器一般用於資源的自動獲取和自動釋放,利用開啟檔案時使用上下文管理器:

with open("test.txt", "w") as f:  # 自動開啟和關閉檔案
    f.write("hello, 我是三木")    #  對檔案進行讀寫

如果要複製檔案的話,需要開啟原始檔和目標檔案,那麼就需要2個上下文管理器,程式碼會寫成這個樣子:

with open("test.txt", "r") as f:  # 開啟第一個檔案
    with open("test_copy.txt", "w") as f_copy:  # 開啟第二個檔案
        content = f.read()  # 從第一個檔案獲取內容
        f_copy.write(content)  # 向第二個檔案寫入內容

在Python3.10中,可以將程式碼精簡一下:

with (
    open("test.txt", "r") as f,  # 開啟第一個檔案
    open("test_copy.txt", "w") as f_copy,  # 開啟第二個檔案
):
    content = f.read()  # 從第一個檔案獲取內容
    f_copy.write(content)  # 向第二個檔案寫入內容

注意變化:

  1. with 只出現了1次
  2. 在同一個程式碼段,有2個上下文管理器ff_copy
  3. 這兩個上下文管理可以互動

此外,還可以更加靈(sao)活(qi)的操作:

with (
    open("test.txt", "r", encoding="utf-8") as f,  # 開啟第一個檔案
    open("test_copy.txt", "w", encoding=f.encoding) as f_copy,  # 開啟第二個檔案
):
    content = f.read()  # 從第一個檔案獲取內容
    f_copy.write(content)  # 向第二個檔案寫入內容

注意細節:在第2個open中,使用了第一個open的結果 :f
公眾號:測試開發研習社

新功能3: 結構模式匹配 (Structural Pattern Matching)

如果你熟悉或使用過php,Java或JavaScript等語言,可能見到switch語句,例如這樣:

today = new Date().getDay();
switch () {
    case 0:
        day = "星期天";
        break;
    case 1:
        day = "星期一";
         break;
    case 2:
        day = "星期二";
         break;
    case 3:
        day = "星期三";
         break;
    case 4:
        day = "星期四";
         break;
    case 5:
        day = "星期五";
         break;
    case 6:
        day = "星期六";
} 

簡單來說:根據x的值,選擇指定的case語句進行執行

過去,Python沒有這樣的語句,所以現在,有了!

today = 1
match  today:
    case 0:
        day = "星期天"
    case 1:
        day = "星期一"
    case 2:
        day = "星期二"
    case 3:
        day = "星期三"
    case 4:
        day = "星期四"
    case 5:
        day = "星期五"
    case 6:
        day = "星期六"
    case _:
        day = "別鬧...一個星期只有七天"

print(day)

輸出

星期一

如果將第一行改為today = 8,則輸出

別鬧...一個星期只有七天

注意:

  1. 匹配順序是從上往下
  2. 找到一個匹配的case後,會停止,所以不需要向JavaScript一樣寫break語句
  3. 如果有多個符合條件的case,後面的case也不會有機會匹配到了
  4. 如果沒有符合條件的匹配,則會執行case_,此_稱之為萬用字元,萬用字元是可選的

關於結構匹配模式(Structural Pattern Matching),可以說是Python 3.10 重量級的新功能,它還有很多高階用法,值得專門一篇文章來進行介紹,這裡就先不展開了。

總之,作為一個遲到了的“switch”,會在其他程式語言中的實踐經驗上進行改進,成符合Python一貫的風格:簡單、靈活、強大。

新變化:效能改進

與所有最新的Python版本一樣,Python 3.10也帶來了一些效能改進。首先是str()bytes()bytearray()建構函式的優化,它們的速度應該提高30%~40%左右(來自 https://bugs.python.org/issue41334)

~ $ ./python3.10 -m pyperf timeit -q --compare-to=python "str()"
Mean +- std dev: [python] 81.9 ns +- 4.5 ns -> [python3.10] 60.0 ns +- 1.9 ns: 1.36x faster (-27%)
~ $ ./python3.10 -m pyperf timeit -q --compare-to=python "bytes()"
Mean +- std dev: [python] 85.1 ns +- 2.2 ns -> [python3.10] 60.2 ns +- 2.3 ns: 1.41x faster (-29%)
~ $ ./python3.10 -m pyperf timeit -q --compare-to=python "bytearray()"
Mean +- std dev: [python] 93.5 ns +- 2.1 ns -> [python3.10] 73.1 ns +- 1.8 ns: 1.28x faster (-22%)

此外,還有多個Python核心模組正在進行持續的優化,讓我們繼續期待吧

新變化:zip支援長度檢查

PEP 618:zip()函式現在具有一個可選strict標誌,用於要求所有可迭代物件具有相等的長度

首先回顧一下zip函式的用法:

在一個迭代中,同時向多個序列讀取內容,

可以將行變成列,列變成行,這類似於轉置矩陣

name_list = ['報警', '急救', '消防']
number_list = [110, 120, 119]

for i in zip(name_list, number_list):
    print(i)

輸出

('報警', 110)
('急救', 120)
('消防', 119)

上面的例子有一個特點:name_listnumber_list 長度是相同的,如果長度不同會怎麼樣呢?

name_list = ['報警', '急救', '消防', '查號']
number_list = [110, 120, 119]

for i in zip(name_list, number_list):
    print(i)

輸出

('報警', 110)
('急救', 120)
('消防', 119)

注意:因為長度不同,所以最後一組結果查號是不會顯示的,但是卻沒有任何提示,從結果來看,無法判斷是否有遺漏的資料。

在Python 3.10,可以給zip()傳遞引數strict=True ,對長度進行嚴格檢查

for i in zip(name_list, number_list, strict=True):
    print(i)

輸出

('報警', 110)
('急救', 120)
('消防', 119)
Traceback (most recent call last):
  File "C:\Users\san\PycharmProjects\py310\a.py", line 4, in <module>
    for i in zip(name_list, number_list, strict=True):
ValueError: zip() argument 2 is shorter than argument 1

注意: zip的第二個引數比第一個引數短,於是丟擲異常


文章首發於我的公眾號,原文連結:https://mp.weixin.qq.com/s/acNtLBNPKUKmcX2VW-K0mw
如果喜歡的話歡迎關注和留言,這是我最大的動力!

相關文章