Python 3.11 正式版發(fā)布了
來(lái)源:
奇酷教育 發(fā)表于:
Python 3 11 正式版發(fā)布了
Error Tracebacks
Python 這門(mén)編程語(yǔ)言對(duì)初學(xué)者非常友好,它具有易于理解的語(yǔ)法和強(qiáng)大的數(shù)據(jù)結(jié)構(gòu)。但對(duì)于剛剛接觸 Python 的人來(lái)說(shuō)卻存在一個(gè)難題,即如何解釋當(dāng) Python 遇到錯(cuò)誤時(shí)顯示的 traceback。
Python 3.11 將 Decorative annotation 添加到 tracebacks 中,以幫助用戶(hù)更快地解釋錯(cuò)誤消息。想要獲得這種功能,可以將以下代碼添加到 inverse.py 文件中。
舉例來(lái)說(shuō),你可以使用 inverse() 來(lái)計(jì)算一個(gè)數(shù)的倒數(shù)。因?yàn)?0 沒(méi)有倒數(shù),所以在運(yùn)行下列代碼時(shí)會(huì)拋出一個(gè)錯(cuò)誤。
注意嵌入在 traceback 中的 ^ 和~ 符號(hào),它們指向?qū)е洛e(cuò)誤的代碼。與此前的 tracebacks 一樣,你應(yīng)該從底層開(kāi)始,然后逐步向上。這種操作對(duì)發(fā)現(xiàn)錯(cuò)誤非常有用,但如果代碼過(guò)于復(fù)雜,帶注釋的 tracebacks 會(huì)更好。
更快的代碼執(zhí)行
Python 以速度慢著稱(chēng),例如在 Python 中,常規(guī)循環(huán)比 C 中的類(lèi)似循環(huán)慢幾個(gè)數(shù)量級(jí)。
Python 官方正在著手改進(jìn)這一缺陷。2020 年秋,Mark Shannon 提出了關(guān)于 Python 的幾個(gè)性能改進(jìn)。這個(gè)提議被稱(chēng)為香農(nóng)計(jì)劃 (Shannon Plan),他們希望通過(guò)幾個(gè)版本的更新將 Python 的速度提高 5 倍。不久之后微軟正式加入該計(jì)劃,該公司正在支持包括 Mark Shannon、Guido van Rossum 在內(nèi)的開(kāi)發(fā)人員,致力于「Faster CPython」項(xiàng)目的研究。
「Faster CPython」項(xiàng)目中的一個(gè)重要提案是 PEP 659,在此基礎(chǔ)上,Python 3.11 有了許多改進(jìn)。
PEP 659 描述了一種「specializing adaptive interpreter」。主要思想是通過(guò)優(yōu)化經(jīng)常執(zhí)行的操作來(lái)加快代碼運(yùn)行速度, 這類(lèi)似于 JIT(just-in-time)編譯。只是它不影響編譯,相反,Python 的字節(jié)碼是動(dòng)態(tài)調(diào)整或可更改的。
研究人員在字節(jié)碼生成中添加了一個(gè)名為「quickening」的新步驟,從而可以在運(yùn)行時(shí)優(yōu)化指令,并將它們替換為 adaptive 指令。
一旦函數(shù)被調(diào)用了一定次數(shù),quickening 指令就會(huì)啟動(dòng)。在 CPython 3.11 中,八次調(diào)用之后就會(huì)啟動(dòng) quickening。你可以通過(guò)調(diào)用 dis() 并設(shè)置 adaptive 參數(shù)來(lái)觀察解釋器如何適應(yīng)字節(jié)碼。
在基準(zhǔn)測(cè)試中,CPython 3.11 比 CPython 3.10 平均快 25%。Faster CPython 項(xiàng)目是一個(gè)正在進(jìn)行的項(xiàng)目,已經(jīng)有幾個(gè)優(yōu)化計(jì)劃在 2023 年 10 月與 Python 3.12 一起發(fā)布。你可以在 GitHub 上關(guān)注該項(xiàng)目。Python 3.12 目標(biāo):還可以更快!
項(xiàng)目地址:https://github.com/faster-cpython/ideas
更好的異步任務(wù)語(yǔ)法
Python 中對(duì)異步編程的支持已經(jīng)發(fā)展了很長(zhǎng)時(shí)間。Python 2 時(shí)代添加了生成器,asyncio 庫(kù)最初是在 Python 3.4 中添加的,而 async 和 await 關(guān)鍵字是在 Python 3.5 中添加的。在 Python 3.11 中,你可以使用任務(wù)組(task groups),它為運(yùn)行和監(jiān)視異步任務(wù)提供了更簡(jiǎn)潔的語(yǔ)法。
改進(jìn)的類(lèi)型變量
Python 是一種動(dòng)態(tài)類(lèi)型語(yǔ)言,但它通過(guò)可選的類(lèi)型提示支持靜態(tài)類(lèi)型。Python 靜態(tài)類(lèi)型系統(tǒng)的基礎(chǔ)在 2015 年的 PEP 484 中定義。自 Python 3.5 以來(lái),每個(gè) Python 版本都引入了幾個(gè)與類(lèi)型相關(guān)的新提案。
Python 3.11 發(fā)布了 5 個(gè)與類(lèi)型相關(guān)的 PEP,創(chuàng)下新高:
PEP 646: 可變泛型
PEP 655: 根據(jù)需要或可能丟失的情況標(biāo)記單個(gè) TypedDict 項(xiàng)
PEP 673: Self 類(lèi)型
PEP 675: 任意文字字符串類(lèi)型
PEP 681: 數(shù)據(jù)類(lèi)轉(zhuǎn)換
支持 TOML 配置解析
TOML 是 Tom's Obvious Minimal Language 的縮寫(xiě)。這是一種在過(guò)去十年中流行起來(lái)的配置文件格式。在為包和項(xiàng)目指定元數(shù)據(jù)時(shí),Python 社區(qū)已將 TOML 作為首選格式。
雖然 TOML 已被使用多年,但 Python 并沒(méi)有內(nèi)置的 TOML 支持。當(dāng) tomllib 添加到標(biāo)準(zhǔn)庫(kù)時(shí),Python 3.11 中的情況發(fā)生了變化。這個(gè)新模塊建立在 toml 第三方庫(kù)之上,允許解析 TOML 文件。
以下是名為 units.toml 的 TOML 文件示例:
其他功能
除了以上主要更新和改進(jìn)之外,Python 3.11 還有更多值得探索的功能,比如更快的程序啟動(dòng)速度、對(duì)異常的更多改變以及對(duì)字符串格式的小幅改進(jìn)。
更快的程序啟動(dòng)速度
Faster CPython 項(xiàng)目的一大成果是實(shí)現(xiàn)了更快的啟動(dòng)時(shí)間。當(dāng)你運(yùn)行 Python 腳本時(shí),解釋器初始化需要一些操作。這就導(dǎo)致即便是最簡(jiǎn)單的程序也需要幾毫秒才能運(yùn)行。
在很多情況下,與運(yùn)行代碼所需時(shí)間相比,啟動(dòng)程序需要的時(shí)間可以忽略不計(jì)。但是在運(yùn)行時(shí)間較短的腳本中,如典型的命令行應(yīng)用程序,啟動(dòng)時(shí)間可能會(huì)顯著影響程序性能。比如考慮如下腳本,它受到了經(jīng)典 cowsay 程序的啟發(fā)。
在 snakesay.py 中,你從命令行讀取一條消息,然后將這條消息打印在帶有一條可愛(ài)蛇的對(duì)話(huà)氣泡中。你可以讓蛇說(shuō)任何話(huà)。這是命令行應(yīng)用程序的基本示例,它運(yùn)行得很快,但仍需要幾毫秒。這一開(kāi)銷(xiāo)的很大部分發(fā)生在 Python 導(dǎo)入模塊時(shí)。
你可以使用 - X importtime 選項(xiàng)來(lái)顯示導(dǎo)入模塊所用的時(shí)間。表中的數(shù)字為微秒為單位,最后一列是模塊名稱(chēng)的格式。
該示例分別運(yùn)行在 Python 3.11 和 3.10 上,結(jié)果如下圖所示,Python 3.11 的導(dǎo)入速度更快,有助于 Python 程序更快地啟動(dòng)。
零成本異常
異常的內(nèi)部表示在 Python 3.11 中有所不同。異常對(duì)象更輕量級(jí),并且異常處理發(fā)生了變化。因此只要不觸發(fā) except 字句,try … except 塊中的開(kāi)銷(xiāo)就越小。
所謂的零成本異常受到了 C++ 和 Java 等其他語(yǔ)言的啟發(fā)。當(dāng)你的源代碼被編譯為字節(jié)碼時(shí),編譯器創(chuàng)建跳轉(zhuǎn)表,由此來(lái)實(shí)現(xiàn)零成本異常。如果引發(fā)異常,查詢(xún)這些跳轉(zhuǎn)表。如果沒(méi)有異常,則 try 塊中的代碼沒(méi)有運(yùn)行時(shí)開(kāi)銷(xiāo)。
異常組
此前,你了解到了任務(wù)組以及它們?nèi)绾瓮瑫r(shí)處理多個(gè)錯(cuò)誤。這都要?dú)w功于一個(gè)被稱(chēng)為異常組的新功能。
我們可以這樣考慮異常組,它們是包裝了其他幾種常規(guī)異常的常規(guī)異常。雖然異常組在很多方面表現(xiàn)得像常規(guī)異常,但它們也支持特殊語(yǔ)法,幫助你有效地處理每個(gè)包裝異常。如下所示,你可以通過(guò)給出一個(gè)描述并列出包裝的異常來(lái)創(chuàng)建一個(gè)異常組。
異常 Notes
常規(guī)異常具有添加任意 notes 的擴(kuò)展能力。你可以使用. add_note() 向任何異常添加一個(gè) note,并通過(guò)檢查.__notes__屬性來(lái)查看現(xiàn)有 notes。
負(fù)零格式化
使用浮點(diǎn)數(shù)進(jìn)行計(jì)算時(shí)可能會(huì)遇到一個(gè)奇怪概念——負(fù)零。你可以觀察到負(fù)零和 regular zero 在 REPL 中呈現(xiàn)不同,如下所示。
更多關(guān)于 Python 3.11 的更新細(xì)節(jié)請(qǐng)參閱原文檔。
原文:https://realpython.com/python311-new-features