Python 3.8 的新特性¶
- 編輯:
Raymond Hettinger
本文介紹了 Python 3.8 相較於 3.7 的新特性。Python 3.8 於 2019 年 10 月 14 日釋出。有關完整詳細資訊,請參閱變更日誌。
摘要 – 版本亮點¶
新特性¶
賦值表示式¶
新的語法 :=
可以在更大的表示式中將值賦給變數。由於它與海象的眼睛和牙齒相似,因此它被親切地稱為 “海象運算子”。
在此示例中,賦值表示式有助於避免兩次呼叫 len()
if (n := len(a)) > 10:
print(f"List is too long ({n} elements, expected <= 10)")
在正則表示式匹配期間,也會出現類似的好處,此時需要兩次匹配物件,一次用於測試是否發生匹配,另一次用於提取子組
discount = 0.0
if (mo := re.search(r'(\d+)% discount', advertisement)):
discount = float(mo.group(1)) / 100.0
該運算子在 while 迴圈中也很有用,這些迴圈計算一個值以測試迴圈終止,然後在迴圈體中再次需要該值
# Loop over fixed length blocks
while (block := f.read(256)) != '':
process(block)
另一個有用的用例出現在列表推導式中,其中在過濾條件中計算的值也需要在表示式主體中使用
[clean_name.title() for name in names
if (clean_name := normalize('NFC', name)) in allowed_names]
嘗試將海象運算子的使用限制在減少複雜性並提高可讀性的簡潔情況下。
有關完整說明,請參閱 PEP 572。
(由 Emily Morehouse 在 bpo-35224 中貢獻。)
僅限位置引數¶
有一個新的函式引數語法 /
,用於指示某些函式引數必須按位置指定,並且不能用作關鍵字引數。這與 help()
為使用 Larry Hastings 的 Argument Clinic 工具註釋的 C 函式顯示的表示法相同。
在以下示例中,引數 a 和 b 是僅限位置的,而 c 或 d 可以是位置或關鍵字,e 或 f 必須是關鍵字
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
以下是有效的呼叫
f(10, 20, 30, d=40, e=50, f=60)
但是,這些是無效的呼叫
f(10, b=20, c=30, d=40, e=50, f=60) # b cannot be a keyword argument
f(10, 20, 30, 40, 50, f=60) # e must be a keyword argument
此表示法的一個用例是,它允許純 Python 函式完全模擬現有 C 編碼函式的行為。例如,內建的 divmod()
函式不接受關鍵字引數
def divmod(a, b, /):
"Emulate the built in divmod() function"
return (a // b, a % b)
另一個用例是在引數名稱沒有幫助時排除關鍵字引數。例如,內建的 len()
函式的簽名是 len(obj, /)
。這避免了諸如此類的尷尬呼叫
len(obj='hello') # The "obj" keyword argument impairs readability
將引數標記為僅限位置的另一個好處是,它允許將來更改引數名稱,而不會有破壞客戶端程式碼的風險。例如,在 statistics
模組中,引數名稱 dist 將來可能會更改。這是透過以下函式規範實現的
def quantiles(dist, /, *, n=4, method='exclusive')
...
由於 /
左側的引數不會作為可能的關鍵字公開,因此引數名稱仍可在 **kwargs
中使用
>>> def f(a, b, /, **kwargs):
... print(a, b, kwargs)
...
>>> f(10, 20, a=1, b=2, c=3) # a and b are used in two ways
10 20 {'a': 1, 'b': 2, 'c': 3}
這大大簡化了需要接受任意關鍵字引數的函式和方法的實現。例如,這是 collections
模組中程式碼的摘錄
class Counter(dict):
def __init__(self, iterable=None, /, **kwds):
# Note "iterable" is a possible keyword argument
有關完整說明,請參閱 PEP 570。
(由 Pablo Galindo 在 bpo-36540 中貢獻。)
編譯位元組碼檔案的並行檔案系統快取¶
新的 PYTHONPYCACHEPREFIX
設定(也可作為 -X
pycache_prefix
提供)配置隱式位元組碼快取以使用單獨的並行檔案系統樹,而不是每個源目錄中的預設 __pycache__
子目錄。
快取的位置在 sys.pycache_prefix
中報告(None
表示 __pycache__
子目錄中的預設位置)。
(由 Carl Meyer 在 bpo-33499 中貢獻。)
除錯構建使用與釋出構建相同的 ABI¶
現在,Python 無論是在釋出模式還是除錯模式下構建,都使用相同的 ABI。在 Unix 上,當 Python 以除錯模式構建時,現在可以載入以釋出模式構建的 C 擴充套件和使用穩定 ABI 構建的 C 擴充套件。
釋出版本和除錯版本現在是 ABI 相容的:定義 Py_DEBUG
宏不再暗示 Py_TRACE_REFS
宏,這引入了唯一的 ABI 不相容性。Py_TRACE_REFS
宏添加了 sys.getobjects()
函式和 PYTHONDUMPREFS
環境變數,可以使用新的 ./configure --with-trace-refs
構建選項設定。(由 Victor Stinner 在 bpo-36465 中貢獻。)
在 Unix 上,C 擴充套件不再連結到 libpython,除非在 Android 和 Cygwin 上。現在,靜態連結的 Python 可以載入使用共享庫 Python 構建的 C 擴充套件。(由 Victor Stinner 在 bpo-21536 中貢獻。)
在 Unix 上,當 Python 以除錯模式構建時,匯入現在還會查詢以釋出模式編譯的 C 擴充套件和使用穩定 ABI 編譯的 C 擴充套件。(由 Victor Stinner 在 bpo-36722 中貢獻。)
要將 Python 嵌入到應用程式中,必須將新的 --embed
選項傳遞給 python3-config --libs --embed
,以獲取 -lpython3.8
(將應用程式連結到 libpython)。為了同時支援 3.8 和更舊的版本,請先嚐試 python3-config --libs --embed
,如果之前的命令失敗,則回退到 python3-config --libs
(不帶 --embed
)。
新增一個 pkg-config python-3.8-embed
模組,以便將 Python 嵌入到應用程式中:pkg-config python-3.8-embed --libs
包含 -lpython3.8
。為了同時支援 3.8 和更舊的版本,請先嚐試 pkg-config python-X.Y-embed --libs
,如果之前的命令失敗,則回退到 pkg-config python-X.Y --libs
(不帶 --embed
)(將 X.Y
替換為 Python 版本)。
另一方面,pkg-config python3.8 --libs
不再包含 -lpython3.8
。C 擴充套件不應連結到 libpython(除非在 Android 和 Cygwin 上,這些情況由指令碼處理);此更改是故意向後不相容的。(由 Victor Stinner 在 bpo-36721 中貢獻。)
f-字串支援 =
,用於自文件化表示式和除錯¶
向f-字串添加了一個 =
說明符。諸如 f'{expr=}'
的 f-字串將展開為表示式的文字、一個等號,然後是已評估表示式的表示。例如
>>> user = 'eric_idle'
>>> member_since = date(1975, 7, 31)
>>> f'{user=} {member_since=}'
"user='eric_idle' member_since=datetime.date(1975, 7, 31)"
通常的 f-字串格式說明符 允許更好地控制表示式結果的顯示方式
>>> delta = date.today() - member_since
>>> f'{user=!s} {delta.days=:,d}'
'user=eric_idle delta.days=16,075'
=
說明符將顯示整個表示式,以便可以顯示計算
>>> print(f'{theta=} {cos(radians(theta))=:.3f}')
theta=30 cos(radians(theta))=0.866
(由 Eric V. Smith 和 Larry Hastings 在 bpo-36817 中貢獻。)
PEP 578:Python 執行時審計鉤子¶
此 PEP 添加了審計鉤子和驗證開放鉤子。兩者都可從 Python 和本機程式碼中使用,允許用純 Python 程式碼編寫的應用程式和框架利用額外的通知,同時還允許嵌入程式或系統管理員部署始終啟用稽核的 Python 版本。
有關完整詳細資訊,請參閱 PEP 578。
PEP 587:Python 初始化配置¶
PEP 587 添加了一個新的 C API 來配置 Python 初始化,從而可以更好地控制整個配置並提供更好的錯誤報告。
新結構
新函式
此 PEP 還向這些內部結構添加了 _PyRuntimeState.preconfig
(PyPreConfig
型別)和 PyInterpreterState.config
(PyConfig
型別)欄位。PyInterpreterState.config
將成為新的參考配置,取代全域性配置變數和其他私有變數。
有關文件,請參閱 Python 初始化配置。
有關完整描述,請參閱 PEP 587。
(由 Victor Stinner 在 bpo-36763 中貢獻。)
PEP 590:Vectorcall:CPython 的快速呼叫協議¶
Vectorcall 協議已新增到 Python/C API 中。它旨在形式化已經為各種類進行的現有最佳化。任何實現可呼叫介面的 靜態型別都可以使用此協議。
這目前是臨時的。目標是在 Python 3.9 中使其完全公開。
有關完整描述,請參閱 PEP 590。
(由 Jeroen Demeyer、Mark Shannon 和 Petr Viktorin 在 bpo-36974 中貢獻。)
帶有帶外資料緩衝區的 Pickle 協議 5¶
當使用 pickle
在 Python 程序之間傳輸大量資料,以利用多核或多機處理時,透過減少記憶體複製來最佳化傳輸非常重要,並且可能透過應用諸如依賴於資料的壓縮之類的自定義技術來最佳化傳輸。
pickle
協議 5 引入了對帶外緩衝區的支援,其中 PEP 3118-相容的資料可以與主 pickle 流分開傳輸,由通訊層酌情決定。
有關完整描述,請參閱 PEP 574。
(由 Antoine Pitrou 在 bpo-36785 中貢獻。)
其他語言變更¶
由於實現中的問題,
finally
子句中的continue
語句是非法的。在 Python 3.8 中,此限制被取消。(由 Serhiy Storchaka 在 bpo-32489 中貢獻。)bool
、int
和fractions.Fraction
型別現在具有與float
和decimal.Decimal
中找到的類似的as_integer_ratio()
方法。此小的 API 擴充套件使得可以編寫numerator, denominator = x.as_integer_ratio()
並且使其在多種數字型別中工作。(由 Lisa Roach 在 bpo-33073 和 Raymond Hettinger 在 bpo-37819 中貢獻。)int
、float
和complex
的建構函式現在將使用__index__()
特殊方法(如果可用),並且當相應的__int__()
、__float__()
或__complex__()
方法不可用時。(由 Serhiy Storchaka 在 bpo-20092 中貢獻。)在
正則表示式
中添加了對\N{name}
轉義的支援。>>> notice = 'Copyright © 2019' >>> copyright_year_pattern = re.compile(r'\N{copyright sign}\s*(\d{4})') >>> int(copyright_year_pattern.search(notice).group(1)) 2019
(由 Jonathan Eunice 和 Serhiy Storchaka 在 bpo-30688 中貢獻。)
現在可以使用
reversed()
以相反的插入順序迭代字典和字典檢視。(由 Rémi Lapeyre 在 bpo-33462 中貢獻。)函式呼叫中關鍵字名稱允許的語法受到了進一步的限制。特別是,不再允許
f((keyword)=arg)
。它從來都不打算允許在關鍵字引數賦值項的左側使用裸名稱。(由 Benjamin Peterson 在 bpo-34641 中貢獻。)在
yield
和return
語句中,泛化的可迭代解包不再需要用圓括號括起來。這使得 *yield* 和 *return* 的語法與普通的賦值語法更加一致。>>> def parse(family): lastname, *members = family.split() return lastname.upper(), *members >>> parse('simpsons homer marge bart lisa maggie') ('SIMPSONS', 'homer', 'marge', 'bart', 'lisa', 'maggie')
(由 David Cuthbert 和 Jordan Chapman 在 bpo-32117 中貢獻。)
當在諸如
[(10, 20) (30, 40)]
之類的程式碼中遺漏逗號時,編譯器會顯示SyntaxWarning
並提供有用的建議。這比僅僅使用指示第一個元組不可呼叫的TypeError
更好。(由 Serhiy Storchaka 在 bpo-15248 中貢獻。)datetime.date
或datetime.datetime
的子類與datetime.timedelta
物件之間的算術運算現在返回子類的例項,而不是基類。這也會影響其實現(直接或間接地)使用datetime.timedelta
算術的運算的返回型別,例如astimezone()
。(由 Paul Ganssle 在 bpo-32417 中貢獻。)當 Python 直譯器被 Ctrl-C (SIGINT) 中斷並且產生的
KeyboardInterrupt
異常未被捕獲時,Python 程序現在將透過 SIGINT 訊號或使用正確的退出程式碼退出,以便呼叫程序可以檢測到它因 Ctrl-C 而終止。POSIX 和 Windows 上的 Shell 使用它來正確終止互動會話中的指令碼。(由 Google 透過 Gregory P. Smith 在 bpo-1054041 中貢獻。)一些高階程式設計風格需要更新現有函式的
types.CodeType
物件。由於程式碼物件是不可變的,因此需要建立一個新的程式碼物件,該物件以現有程式碼物件為模型。使用 19 個引數,這有點繁瑣。現在,新的replace()
方法可以建立帶有少量更改引數的克隆。這是一個示例,它更改了
statistics.mean()
函式,以防止 data 引數用作關鍵字引數>>> from statistics import mean >>> mean(data=[10, 20, 90]) 40 >>> mean.__code__ = mean.__code__.replace(co_posonlyargcount=1) >>> mean(data=[10, 20, 90]) Traceback (most recent call last): ... TypeError: mean() got some positional-only arguments passed as keyword arguments: 'data'
(由 Victor Stinner 在 bpo-37032 中貢獻。)
對於整數,
pow()
函式的三引數形式現在允許當底數與模數互質時指數為負數。當指數為-1
時,它計算底數的模逆,對於其他負指數,計算該逆的適當冪。例如,要計算 38 模 137 的模乘逆,請寫>>> pow(38, -1, 137) 119 >>> 119 * 38 % 137 1
模逆出現在線性丟番圖方程的解中。例如,要找到
4258𝑥 + 147𝑦 = 369
的整數解,首先將其重寫為4258𝑥 ≡ 369 (mod 147)
,然後求解>>> x = 369 * pow(4258, -1, 147) % 147 >>> y = (4258 * x - 369) // -147 >>> 4258 * x + 147 * y 369
(由 Mark Dickinson 在 bpo-36027 中貢獻。)
字典推導式已與字典字面量同步,因此先計算鍵,然後再計算值。
>>> # Dict comprehension >>> cast = {input('role? '): input('actor? ') for i in range(2)} role? King Arthur actor? Chapman role? Black Knight actor? Cleese >>> # Dict literal >>> cast = {input('role? '): input('actor? ')} role? Sir Robin actor? Eric Idle
保證的執行順序對於賦值表示式很有幫助,因為在鍵表示式中賦值的變數將在值表示式中可用。
>>> names = ['Martin von Löwis', 'Łukasz Langa', 'Walter Dörwald'] >>> {(n := normalize('NFC', name)).casefold() : n for name in names} {'martin von löwis': 'Martin von Löwis', 'łukasz langa': 'Łukasz Langa', 'walter dörwald': 'Walter Dörwald'}
(由 Jörn Heissler 在 bpo-35224 中貢獻。)
object.__reduce__()
方法現在可以返回一個長度為 2 到 6 個元素的元組。以前,限制為 5 個。新的可選的第六個元素是具有(obj, state)
簽名的可呼叫物件。這允許直接控制特定物件的狀態更新行為。如果不是 None,則此可呼叫物件將優先於物件的__setstate__()
方法。(由 Pierre Glaser 和 Olivier Grisel 在 bpo-35900 中貢獻。)
新模組¶
新的
importlib.metadata
模組為讀取第三方包的元資料提供了(臨時的)支援。例如,它可以提取已安裝包的版本號、入口點列表等。>>> # Note following example requires that the popular "requests" >>> # package has been installed. >>> >>> from importlib.metadata import version, requires, files >>> version('requests') '2.22.0' >>> list(requires('requests')) ['chardet (<3.1.0,>=3.0.2)'] >>> list(files('requests'))[:5] [PackagePath('requests-2.22.0.dist-info/INSTALLER'), PackagePath('requests-2.22.0.dist-info/LICENSE'), PackagePath('requests-2.22.0.dist-info/METADATA'), PackagePath('requests-2.22.0.dist-info/RECORD'), PackagePath('requests-2.22.0.dist-info/WHEEL')]
(由 Barry Warsaw 和 Jason R. Coombs 在 bpo-34632 中貢獻。)
改進的模組¶
ast¶
AST 節點現在具有 end_lineno
和 end_col_offset
屬性,這些屬性給出了節點末端的精確位置。(這僅適用於具有 lineno
和 col_offset
屬性的節點。)
新函式 ast.get_source_segment()
返回特定 AST 節點的原始碼。
(由 Ivan Levkivskyi 在 bpo-33416 中貢獻。)
ast.parse()
函式有一些新的標誌。
type_comments=True
會使其返回與某些 AST 節點關聯的 PEP 484 和 PEP 526 型別註釋的文字;mode='func_type'
可用於解析 PEP 484 “簽名型別註釋”(為函式定義 AST 節點返回);feature_version=(3, N)
允許指定更早的 Python 3 版本。例如,feature_version=(3, 4)
會將async
和await
視為非保留字。
(由 Guido van Rossum 在 bpo-35766 中貢獻。)
asyncio¶
asyncio.run()
已從臨時 API 升級為穩定 API。此函式可用於執行 協程 並返回結果,同時自動管理事件迴圈。例如
import asyncio
async def main():
await asyncio.sleep(0)
return 42
asyncio.run(main())
這大致等同於
import asyncio
async def main():
await asyncio.sleep(0)
return 42
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(main())
finally:
asyncio.set_event_loop(None)
loop.close()
實際實現要複雜得多。因此,asyncio.run()
應該是執行 asyncio 程式的首選方式。
(由 Yury Selivanov 在 bpo-32314 中貢獻。)
執行 python -m asyncio
會啟動一個原生非同步 REPL。這允許快速嘗試具有頂級 await
的程式碼。不再需要直接呼叫 asyncio.run()
,這會在每次呼叫時生成一個新的事件迴圈
$ python -m asyncio
asyncio REPL 3.8.0
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> await asyncio.sleep(10, result='hello')
hello
(由 Yury Selivanov 在 bpo-37028 中貢獻。)
異常 asyncio.CancelledError
現在繼承自 BaseException
而不是 Exception
,並且不再繼承自 concurrent.futures.CancelledError
。(由 Yury Selivanov 在 bpo-32528 中貢獻。)
在 Windows 上,預設事件迴圈現在是 ProactorEventLoop
。(由 Victor Stinner 在 bpo-34687 中貢獻。)
ProactorEventLoop
現在還支援 UDP。(由 Adam Meily 和 Andrew Svetlov 在 bpo-29883 中貢獻。)
ProactorEventLoop
現在可以透過 KeyboardInterrupt
(“CTRL+C”) 中斷。(由 Vladimir Matveev 在 bpo-23057 中貢獻。)
添加了 asyncio.Task.get_coro()
用於獲取 asyncio.Task
內包裝的協程。(由 Alex Grönholm 在 bpo-36999 中貢獻。)
Asyncio 任務現在可以透過將 name
關鍵字引數傳遞給 asyncio.create_task()
或 create_task()
事件迴圈方法,或者透過在任務物件上呼叫 set_name()
方法來命名。任務名稱在 asyncio.Task
的 repr()
輸出中可見,也可以使用 get_name()
方法檢索。(由 Alex Grönholm 在 bpo-34270 中貢獻。)
為 asyncio.loop.create_connection()
添加了對 Happy Eyeballs 的支援。為了指定行為,添加了兩個新引數:happy_eyeballs_delay 和 interleave。Happy Eyeballs 演算法透過嘗試同時使用 IPv4 和 IPv6 連線來提高支援 IPv4 和 IPv6 的應用程式的響應能力。(由 twisteroid ambassador 在 bpo-33530 中貢獻。)
builtins¶
compile()
內建函式已得到改進,可以接受 ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
標誌。透過傳遞這個新標誌,compile()
將允許通常被認為是無效語法的頂級 await
、async for
和 async with
構造。然後可能會返回標記有 CO_COROUTINE
標誌的非同步程式碼物件。(由 Matthias Bussonnier 在 bpo-34616 中貢獻)
collections¶
_asdict()
方法用於 collections.namedtuple()
現在返回 dict
而不是 collections.OrderedDict
。這是可行的,因為自 Python 3.7 以來,常規 dict 保證了排序。如果需要 OrderedDict
的額外功能,建議的補救方法是將結果強制轉換為所需的型別:OrderedDict(nt._asdict())
。(由 Raymond Hettinger 在 bpo-35864 中貢獻。)
cProfile¶
cProfile.Profile
類現在可以用作上下文管理器。透過執行以下程式碼來分析程式碼塊
import cProfile
with cProfile.Profile() as profiler:
# code to be profiled
...
(由 Scott Sanderson 在 bpo-29235 中貢獻。)
csv¶
csv.DictReader
現在返回 dict
的例項,而不是 collections.OrderedDict
。該工具現在更快,使用更少的記憶體,同時仍然保留欄位順序。(由 Michael Selik 在 bpo-34003 中貢獻。)
curses¶
為底層 ncurses 庫添加了一個新的變數,用於儲存結構化的版本資訊:ncurses_version
。(由 Serhiy Storchaka 在 bpo-31680 中貢獻。)
ctypes¶
在 Windows 上,CDLL
及其子類現在接受一個 winmode 引數,用於為底層的 LoadLibraryEx
呼叫指定標誌。預設標誌設定為僅從可信位置載入 DLL 依賴項,包括 DLL 儲存的路徑(如果使用完整或部分路徑載入初始 DLL)以及透過 add_dll_directory()
新增的路徑。(由 Steve Dower 在 bpo-36085 中貢獻。)
datetime¶
添加了新的替代建構函式 datetime.date.fromisocalendar()
和 datetime.datetime.fromisocalendar()
,它們分別從 ISO 年、週數和星期幾構造 date
和 datetime
物件;這些是每個類的 isocalendar
方法的逆操作。(由 Paul Ganssle 在 bpo-36004 中貢獻。)
functools¶
functools.lru_cache()
現在可以用作直接裝飾器,而不是返回裝飾器的函式。因此,現在支援以下兩種方式:
@lru_cache
def f(x):
...
@lru_cache(maxsize=256)
def f(x):
...
(由 Raymond Hettinger 在 bpo-36772 中貢獻。)
添加了一個新的 functools.cached_property()
裝飾器,用於快取例項生命週期內的計算屬性。
import functools
import statistics
class Dataset:
def __init__(self, sequence_of_numbers):
self.data = sequence_of_numbers
@functools.cached_property
def variance(self):
return statistics.variance(self.data)
(由 Carl Meyer 在 bpo-21145 中貢獻)
添加了一個新的 functools.singledispatchmethod()
裝飾器,它使用 單分派 將方法轉換為 泛型函式
from functools import singledispatchmethod
from contextlib import suppress
class TaskManager:
def __init__(self, tasks):
self.tasks = list(tasks)
@singledispatchmethod
def discard(self, value):
with suppress(ValueError):
self.tasks.remove(value)
@discard.register(list)
def _(self, tasks):
targets = set(tasks)
self.tasks = [x for x in self.tasks if x not in targets]
(由 Ethan Smith 在 bpo-32380 中貢獻)
gc¶
get_objects()
現在可以接收一個可選的 generation 引數,指示要從中獲取物件的代數。(由 Pablo Galindo 在 bpo-36016 中貢獻。)
gettext¶
添加了 pgettext()
及其變體。(由 Franz Glasner、Éric Araujo 和 Cheryl Sabella 在 bpo-2504 中貢獻。)
gzip¶
為 gzip.compress()
添加了 mtime 引數,以實現可重現的輸出。(由 Guo Ci Teo 在 bpo-34898 中貢獻。)
現在,對於某些型別的無效或損壞的 gzip 檔案,會引發 BadGzipFile
異常,而不是 OSError
。(由 Filip Gruszczyński、Michele Orrù 和 Zackery Spytz 在 bpo-6584 中貢獻。)
IDLE 和 idlelib¶
超過 N 行(預設為 50)的輸出將被壓縮成一個按鈕。N 可以在“設定”對話方塊的“常規”頁面的“PyShell”部分中更改。可以透過右鍵單擊輸出來壓縮較少但可能非常長的行。可以透過雙擊按鈕來就地展開壓縮的輸出,或者透過右鍵單擊按鈕將其展開到剪貼簿或單獨的視窗中。(由 Tal Einat 在 bpo-1529353 中貢獻。)
將“執行自定義”新增到“執行”選單,以使用自定義設定執行模組。輸入的任何命令列引數都將新增到 sys.argv 中。它們也會在下次自定義執行時重新出現在框中。還可以禁止正常的 Shell 主模組重啟。(由 Cheryl Sabella、Terry Jan Reedy 和其他人在 bpo-5680 和 bpo-37627 中貢獻。)
為 IDLE 編輯器視窗添加了可選的行號。預設情況下,視窗在不顯示行號的情況下開啟,除非在配置對話方塊的“常規”選項卡中另行設定。現有視窗的行號在“選項”選單中顯示和隱藏。(由 Tal Einat 和 Saimadhav Heblikar 在 bpo-17535 中貢獻。)
現在使用作業系統本機編碼在 Python 字串和 Tcl 物件之間進行轉換。這允許 IDLE 使用 emoji 和其他非 BMP 字元。這些字元可以顯示或複製並貼上到剪貼簿或從剪貼簿複製並貼上。現在,將字串從 Tcl 轉換為 Python 並返回時永遠不會失敗。(許多人為此工作了八年,但這個問題最終由 Serhiy Storchaka 在 bpo-13153 中解決。)
3.8.1 中的新增功能
添加了關閉游標閃爍的選項。(由 Zackery Spytz 在 bpo-4603 中貢獻。)
現在,按 Escape 鍵會關閉 IDLE 完成視窗。(由 Johnny Najera 在 bpo-38944 中貢獻。)
以上更改已向後移植到 3.7 維護版本。
將關鍵字新增到模組名稱完成列表中。(由 Terry J. Reedy 在 bpo-37765 中貢獻。)
inspect¶
如果 __slots__
屬性是值是文件字串的 dict
,則 inspect.getdoc()
函式現在可以查詢 __slots__
的文件字串。這提供了類似於我們已經為 property()
、classmethod()
和 staticmethod()
提供的文件選項
class AudioClip:
__slots__ = {'bit_rate': 'expressed in kilohertz to one decimal place',
'duration': 'in seconds, rounded up to an integer'}
def __init__(self, bit_rate, duration):
self.bit_rate = round(bit_rate / 1000.0, 1)
self.duration = ceil(duration)
(由 Raymond Hettinger 在 bpo-36326 中貢獻。)
io¶
在開發模式 (-X
env
) 和在 除錯構建 中,如果 close()
方法失敗,io.IOBase
終結器現在會記錄異常。預設情況下,在釋出版本中,異常會被靜默忽略。(由 Victor Stinner 在 bpo-18748 中貢獻。)
itertools¶
itertools.accumulate()
函式添加了一個可選的 initial 關鍵字引數來指定初始值
>>> from itertools import accumulate
>>> list(accumulate([10, 5, 30, 15], initial=1000))
[1000, 1010, 1015, 1045, 1060]
(由 Lisa Roach 在 bpo-34659 中貢獻。)
json.tool¶
新增選項 --json-lines
以將每個輸入行解析為單獨的 JSON 物件。(由 Weipeng Hong 在 bpo-31553 中貢獻。)
logging¶
為 logging.basicConfig()
添加了一個 force 關鍵字引數。當設定為 true 時,在執行其他引數指定的配置之前,將刪除並關閉附加到根記錄器的任何現有處理程式。
這解決了一個長期存在的問題。一旦呼叫了記錄器或 basicConfig(),後續對 basicConfig() 的呼叫將被靜默忽略。這使得使用互動式提示符或 Jupyter 筆記本更新、試驗或教授各種日誌記錄配置選項變得很困難。
(由 Raymond Hettinger 建議,Donghee Na 實現,Vinay Sajip 在 bpo-33897 中審閱。)
math¶
添加了新函式 math.dist()
,用於計算兩點之間的歐幾里得距離。(由 Raymond Hettinger 在 bpo-33089 中貢獻。)
擴充套件了 math.hypot()
函式以處理多個維度。以前,它只支援 2-D 情況。(由 Raymond Hettinger 在 bpo-33089 中貢獻。)
添加了新函式 math.prod()
,作為 sum()
的類似函式,它返回一個 ‘start’ 值(預設為 1)乘以一個數字可迭代物件的結果
>>> prior = 0.8
>>> likelihoods = [0.625, 0.84, 0.30]
>>> math.prod(likelihoods, start=prior)
0.126
(由 Pablo Galindo 在 bpo-35606 中貢獻。)
增加了兩個新的組合數學函式 math.perm()
和 math.comb()
>>> math.perm(10, 3) # Permutations of 10 things taken 3 at a time
720
>>> math.comb(10, 3) # Combinations of 10 things taken 3 at a time
120
(由 Yash Aggarwal、Keller Fuchs、Serhiy Storchaka 和 Raymond Hettinger 在 bpo-37128、bpo-37178 和 bpo-35431 中貢獻。)
增加了一個新函式 math.isqrt()
,用於計算精確的整數平方根,而無需轉換為浮點數。新函式支援任意大的整數。它比 floor(sqrt(n))
快,但比 math.sqrt()
慢。
>>> r = 650320427
>>> s = r ** 2
>>> isqrt(s - 1) # correct
650320426
>>> floor(sqrt(s - 1)) # incorrect
650320427
(由 Mark Dickinson 在 bpo-36887 中貢獻。)
函式 math.factorial()
不再接受非 int-like 的引數。(由 Pablo Galindo 在 bpo-33083 中貢獻。)
mmap¶
mmap.mmap
類現在有一個 madvise()
方法來訪問 madvise()
系統呼叫。(由 Zackery Spytz 在 bpo-32941 中貢獻。)
multiprocessing¶
添加了新的 multiprocessing.shared_memory
模組。(由 Davin Potts 在 bpo-35813 中貢獻。)
在 macOS 上,預設使用 spawn 啟動方法。(由 Victor Stinner 在 bpo-33725 中貢獻。)
os¶
在 Windows 上添加了新函式 add_dll_directory()
,用於在匯入擴充套件模組或使用 ctypes
載入 DLL 時提供額外的本機依賴項搜尋路徑。(由 Steve Dower 在 bpo-36085 中貢獻。)
添加了一個新的 os.memfd_create()
函式來包裝 memfd_create()
系統呼叫。(由 Zackery Spytz 和 Christian Heimes 在 bpo-26836 中貢獻。)
在 Windows 上,處理重分析點(包括符號連結和目錄連線)的大部分手動邏輯已委託給作業系統。具體來說,os.stat()
現在將遍歷作業系統支援的任何內容,而 os.lstat()
將僅開啟標識為“名稱代理”的重分析點,而其他重分析點將像 os.stat()
一樣開啟。在所有情況下,stat_result.st_mode
僅對符號連結設定 S_IFLNK
,而不對其他型別的重分析點設定。要識別其他型別的重分析點,請檢查新的 stat_result.st_reparse_tag
屬性。
在 Windows 上,os.readlink()
現在能夠讀取目錄連線。請注意,islink()
對於目錄連線將返回 False
,因此首先檢查 islink
的程式碼將繼續將連線視為目錄,而處理來自 os.readlink()
的錯誤的程式碼現在可能會將連線視為連結。
(由 Steve Dower 在 bpo-37834 中貢獻。)
os.path¶
返回布林結果的 os.path
函式,如 exists()
、lexists()
、isdir()
、isfile()
、islink()
和 ismount()
,現在對於包含在作業系統級別無法表示的字元或位元組的路徑,將返回 False
,而不是引發 ValueError
或其子類 UnicodeEncodeError
和 UnicodeDecodeError
。(由 Serhiy Storchaka 在 bpo-33721 中貢獻。)
Windows 上的 expanduser()
現在更傾向於使用 USERPROFILE
環境變數,而不是使用 HOME
,後者通常不為常規使用者帳戶設定。(由 Anthony Sottile 在 bpo-36264 中貢獻。)
Windows 上的 isdir()
不再為指向不存在的目錄的連結返回 True
。
Windows 上的 realpath()
現在會解析重分析點,包括符號連結和目錄連線。
(由 Steve Dower 在 bpo-37834 中貢獻。)
pathlib¶
返回布林結果的 pathlib.Path
方法,如 exists()
、is_dir()
、is_file()
、is_mount()
、is_symlink()
、is_block_device()
、is_char_device()
、is_fifo()
、is_socket()
,現在對於包含在作業系統級別無法表示的字元的路徑,將返回 False
,而不是引發 ValueError
或其子類 UnicodeEncodeError
。(由 Serhiy Storchaka 在 bpo-33721 中貢獻。)
添加了 pathlib.Path.link_to()
,用於建立一個指向路徑的硬連結。(由 Joannah Nanjekye 在 bpo-26978 中貢獻) 請注意,link_to
在 3.10 中被棄用,並在 3.12 中被刪除,取而代之的是在 3.10 中新增的 hardlink_to
方法,該方法匹配現有 symlink_to
方法的語義。
pickle¶
繼承自 C 最佳化的 Pickler
的 pickle
擴充套件現在可以透過定義特殊的 reducer_override()
方法來覆蓋函式和類的 pickling 邏輯。(由 Pierre Glaser 和 Olivier Grisel 在 bpo-35900 中貢獻。)
plistlib¶
添加了新的 plistlib.UID
,並支援讀取和寫入 NSKeyedArchiver 編碼的二進位制 plist。(由 Jon Janzen 在 bpo-26707 中貢獻。)
pprint¶
pprint
模組為多個函式添加了 sort_dicts 引數。預設情況下,這些函式在渲染或列印之前繼續對字典進行排序。但是,如果將 sort_dicts 設定為 false,則字典會保留鍵插入的順序。這在除錯期間與 JSON 輸入進行比較時很有用。
此外,還有一個方便的新函式 pprint.pp()
,它類似於 pprint.pprint()
,但 sort_dicts 預設值為 False
。
>>> from pprint import pprint, pp
>>> d = dict(source='input.txt', operation='filter', destination='output.txt')
>>> pp(d, width=40) # Original order
{'source': 'input.txt',
'operation': 'filter',
'destination': 'output.txt'}
>>> pprint(d, width=40) # Keys sorted alphabetically
{'destination': 'output.txt',
'operation': 'filter',
'source': 'input.txt'}
(由 Rémi Lapeyre 在 bpo-30670 中貢獻。)
py_compile¶
py_compile.compile()
現在支援靜默模式。(由 Joannah Nanjekye 在 bpo-22640 中貢獻。)
shlex¶
新的 shlex.join()
函式充當 shlex.split()
的反向操作。(由 Bo Bayles 在 bpo-32102 中貢獻。)
shutil¶
shutil.copytree()
現在接受一個新的 dirs_exist_ok
關鍵字引數。(由 Josh Bronson 在 bpo-20849 中貢獻。)
shutil.make_archive()
現在預設為新的存檔使用現代 pax (POSIX.1-2001) 格式,以提高可移植性和標準一致性,這繼承自對 tarfile
模組的相應更改。(由 C.A.M. Gerlach 在 bpo-30661 中貢獻。)
Windows 上的 shutil.rmtree()
現在刪除目錄連線,而不會首先遞迴刪除其內容。(由 Steve Dower 在 bpo-37834 中貢獻。)
socket¶
添加了 create_server()
和 has_dualstack_ipv6()
便利函式,以自動化建立伺服器套接字時通常涉及的必要任務,包括在同一套接字上接受 IPv4 和 IPv6 連線。(由 Giampaolo Rodolà 在 bpo-17561 中貢獻。)
socket.if_nameindex()
、socket.if_nametoindex()
和 socket.if_indextoname()
函式已在 Windows 上實現。(由 Zackery Spytz 在 bpo-37007 中貢獻。)
ssl¶
添加了 post_handshake_auth
以啟用和 verify_client_post_handshake()
來啟動 TLS 1.3 後握手身份驗證。(由 Christian Heimes 在 bpo-34670 中貢獻。)
statistics¶
添加了 statistics.fmean()
,它是 statistics.mean()
的更快、浮點變體。(由 Raymond Hettinger 和 Steven D’Aprano 在 bpo-35904 中貢獻。)
添加了 statistics.geometric_mean()
(由 Raymond Hettinger 在 bpo-27181 中貢獻。)
添加了 statistics.multimode()
,它返回最常見值的列表。(由 Raymond Hettinger 在 bpo-35892 中貢獻。)
添加了 statistics.quantiles()
,它將資料或分佈劃分為等機率區間(例如,四分位數、十分位數或百分位數)。(由 Raymond Hettinger 在 bpo-36546 中貢獻。)
添加了 statistics.NormalDist
,這是一個用於建立和操作隨機變數正態分佈的工具。(由 Raymond Hettinger 在 bpo-36018 中貢獻。)
>>> temperature_feb = NormalDist.from_samples([4, 12, -3, 2, 7, 14])
>>> temperature_feb.mean
6.0
>>> temperature_feb.stdev
6.356099432828281
>>> temperature_feb.cdf(3) # Chance of being under 3 degrees
0.3184678262814532
>>> # Relative chance of being 7 degrees versus 10 degrees
>>> temperature_feb.pdf(7) / temperature_feb.pdf(10)
1.2039930378537762
>>> el_niño = NormalDist(4, 2.5)
>>> temperature_feb += el_niño # Add in a climate effect
>>> temperature_feb
NormalDist(mu=10.0, sigma=6.830080526611674)
>>> temperature_feb * (9/5) + 32 # Convert to Fahrenheit
NormalDist(mu=50.0, sigma=12.294144947901014)
>>> temperature_feb.samples(3) # Generate random samples
[7.672102882379219, 12.000027119750287, 4.647488369766392]
sys¶
新增新的 sys.unraisablehook()
函式,可以重寫以控制如何處理“無法引發的異常”。當發生異常但 Python 無法處理時,會呼叫此函式。例如,當解構函式引發異常或在垃圾回收期間 (gc.collect()
)。(由 Victor Stinner 在 bpo-36829 中貢獻。)
tarfile¶
tarfile
模組現在預設為新的存檔使用現代 pax (POSIX.1-2001) 格式,而不是以前的 GNU 特定格式。這透過在標準且可擴充套件的格式中使用一致的編碼 (UTF-8) 提高了跨平臺的可移植性,並提供了其他一些好處。(由 C.A.M. Gerlach 在 bpo-36268 中貢獻。)
threading¶
新增一個新的 threading.excepthook()
函式,用於處理未捕獲的 threading.Thread.run()
異常。可以重寫它以控制如何處理未捕獲的 threading.Thread.run()
異常。(由 Victor Stinner 在 bpo-1230540 中貢獻。)
為 threading.Thread
類添加了一個新的 threading.get_native_id()
函式和一個 native_id
屬性。這些返回核心分配的當前執行緒的本機整數執行緒 ID。此功能僅在某些平臺上可用,有關詳細資訊,請參閱 get_native_id
。(由 Jake Tesler 在 bpo-36084 中貢獻。)
tokenize¶
當提供的輸入不以換行符結尾時,tokenize
模組現在會隱式地發出一個 NEWLINE
令牌。此行為現在與 C 詞法分析器在內部執行的操作相匹配。(由 Ammar Askar 在 bpo-33899 中貢獻。)
tkinter¶
在 tkinter.Spinbox
類中添加了方法 selection_from()
,selection_present()
,selection_range()
和 selection_to()
。(由 Juliette Monsel 在 bpo-34829 中貢獻。)
在 tkinter.Canvas
類中添加了方法 moveto()
。(由 Juliette Monsel 在 bpo-23831 中貢獻。)
tkinter.PhotoImage
類現在具有 transparency_get()
和 transparency_set()
方法。(由 Zackery Spytz 在 bpo-25451 中貢獻。)
time¶
為 macOS 10.12 添加了新的時鐘 CLOCK_UPTIME_RAW
。(由 Joannah Nanjekye 在 bpo-35702 中貢獻。)
typing¶
typing
模組包含多個新功能
具有每個鍵型別的字典型別。 請參閱 PEP 589 和
typing.TypedDict
。 TypedDict 僅使用字串鍵。預設情況下,每個鍵都必須存在。 指定“total=False”以允許鍵是可選的class Location(TypedDict, total=False): lat_long: tuple grid_square: str xy_coordinate: tuple
字面型別。請參閱 PEP 586 和
typing.Literal
。字面型別表示引數或返回值被限制為一個或多個特定的字面值def get_status(port: int) -> Literal['connected', 'disconnected']: ...
“Final” 變數、函式、方法和類。請參閱 PEP 591,
typing.Final
和typing.final()
。final 限定符指示靜態型別檢查器限制子類化、覆蓋或重新賦值pi: Final[float] = 3.1415926536
協議定義。請參閱 PEP 544,
typing.Protocol
和typing.runtime_checkable()
。諸如typing.SupportsInt
之類的簡單 ABC 現在是Protocol
子類。新的協議類
typing.SupportsIndex
。
unicodedata¶
unicodedata
模組已升級為使用 Unicode 12.1.0 版本。
新函式 is_normalized()
可用於驗證字串是否為特定的標準形式,這通常比實際標準化字串快得多。(由 Max Belanger、David Euresti 和 Greg Price 在 bpo-32285 和 bpo-37966 中貢獻。)
unittest¶
添加了 AsyncMock
以支援 Mock
的非同步版本。 還添加了適當的新斷言函式用於測試。(由 Lisa Roach 在 bpo-26467 中貢獻。)
為 unittest 添加了 addModuleCleanup()
和 addClassCleanup()
,以支援 setUpModule()
和 setUpClass()
的清理。(由 Lisa Roach 在 bpo-24412 中貢獻。)
幾個 mock 斷言函式現在在失敗時還會列印實際呼叫的列表。(由 Petter Strandmark 在 bpo-35047 中貢獻。)
unittest
模組增加了對使用 unittest.IsolatedAsyncioTestCase
作為測試用例的協程的支援。(由 Andrew Svetlov 在 bpo-32972 中貢獻。)
示例
import unittest
class TestRequest(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
self.connection = await AsyncConnection()
async def test_get(self):
response = await self.connection.get("https://example.com")
self.assertEqual(response.status_code, 200)
async def asyncTearDown(self):
await self.connection.close()
if __name__ == "__main__":
unittest.main()
venv¶
venv
現在在所有平臺上都包含一個 Activate.ps1
指令碼,用於在 PowerShell Core 6.1 下啟用虛擬環境。(由 Brett Cannon 在 bpo-32718 中貢獻。)
weakref¶
weakref.proxy()
返回的代理物件現在除了其他數字運算子外,還支援矩陣乘法運算子 @
和 @=
。(由 Mark Dickinson 在 bpo-36669 中貢獻。)
xml¶
作為對 DTD 和外部實體檢索的緩解措施,xml.dom.minidom
和 xml.sax
模組預設不再處理外部實體。(由 Christian Heimes 在 bpo-17239 中貢獻。)
xml.etree.ElementTree
模組中的 .find*()
方法支援萬用字元搜尋,如 {*}tag
,它忽略名稱空間,以及 {namespace}*
,它返回給定名稱空間中的所有標籤。(由 Stefan Behnel 在 bpo-28238 中貢獻。)
xml.etree.ElementTree
模組提供了一個新函式 –xml.etree.ElementTree.canonicalize()
,它實現了 C14N 2.0。(由 Stefan Behnel 在 bpo-13611 中貢獻。)
xml.etree.ElementTree.XMLParser
的目標物件可以透過新的回撥方法 start_ns()
和 end_ns()
接收名稱空間宣告事件。此外,可以將 xml.etree.ElementTree.TreeBuilder
目標配置為處理關於註釋和處理指令的事件,以將其包含在生成的樹中。(由 Stefan Behnel 在 bpo-36676 和 bpo-36673 中貢獻。)
xmlrpc¶
xmlrpc.client.ServerProxy
現在支援一個可選的 headers 關鍵字引數,用於指定隨每個請求傳送的 HTTP 標頭序列。 除此之外,這使得從預設的基本身份驗證升級到更快的會話身份驗證成為可能。(由 Cédric Krier 在 bpo-35153 中貢獻。)
最佳化¶
subprocess
模組現在可以在某些情況下使用os.posix_spawn()
函式以獲得更好的效能。目前,僅當滿足以下所有條件時,它才在 macOS 和 Linux(使用 glibc 2.24 或更高版本)上使用close_fds 為 false;
未設定 preexec_fn、pass_fds、cwd 和 start_new_session 引數;
executable 路徑包含目錄。
(由 Joannah Nanjekye 和 Victor Stinner 在 bpo-35537 中貢獻。)
shutil.copyfile()
,shutil.copy()
,shutil.copy2()
,shutil.copytree()
和shutil.move()
在 Linux 和 macOS 上使用特定於平臺的“快速複製”系統呼叫,以便更有效地複製檔案。“快速複製”意味著複製操作發生在核心中,避免了像 “outfd.write(infd.read())
” 那樣在 Python 中使用使用者空間緩衝區。在 Windows 上,shutil.copyfile()
使用更大的預設緩衝區大小(1 MiB 而不是 16 KiB)和一個基於memoryview()
的shutil.copyfileobj()
變體。在同一分割槽內複製 512 MiB 檔案時,速度在 Linux 上提高約 +26%,在 macOS 上提高約 +50%,在 Windows 上提高約 +40%。此外,消耗的 CPU 週期也少得多。請參閱 平臺相關的有效複製操作 部分。(由 Giampaolo Rodolà 在 bpo-33671 中貢獻。)shutil.copytree()
使用os.scandir()
函式,並且所有依賴於它的複製函式都使用快取的os.stat()
值。複製包含 8000 個檔案的目錄的速度在 Linux 上提高了約 +9%,在 Windows 上提高了約 +20%,在 Windows SMB 共享上提高了約 +30%。此外,os.stat()
系統呼叫的數量減少了 38%,這使得shutil.copytree()
在網路檔案系統上尤其更快。(由 Giampaolo Rodolà 在 bpo-33695 中貢獻。)pickle
模組中的預設協議現在是 Protocol 4,它最早在 Python 3.4 中引入。 與自 Python 3.0 起可用的 Protocol 3 相比,它提供了更好的效能和更小的尺寸。從
PyGC_Head
中刪除了一個Py_ssize_t
成員。 所有 GC 跟蹤的物件(例如元組、列表、字典)的大小都減少了 4 或 8 個位元組。(由 Inada Naoki 在 bpo-33597 中貢獻。)uuid.UUID
現在使用__slots__
來減少其記憶體佔用。(由 Wouter Bolsterlee 和 Tal Einat 在 bpo-30977 中貢獻)將
operator.itemgetter()
的效能提高了 33%。優化了引數處理,併為元組中單個非負整數索引的常見情況(這是標準庫中的典型用例)添加了快速路徑。(由 Raymond Hettinger 在 bpo-35664 中貢獻。)加快了
collections.namedtuple()
中的欄位查詢。它們現在快了兩倍以上,使其成為 Python 中最快的例項變數查詢形式。(由 Raymond Hettinger、Pablo Galindo 和 Joe Jevnik、Serhiy Storchaka 在 bpo-32492 中貢獻。)如果輸入的可迭代物件具有已知的長度(輸入實現了
__len__
),則list
建構函式不會過度分配內部專案緩衝區。這使得建立的列表平均小 12%。(由 Raymond Hettinger 和 Pablo Galindo 在 bpo-33234 中貢獻。)類變數寫入的速度提高了一倍。當更新非雙下劃線屬性時,會不必要地呼叫更新槽。(由 Stefan Behnel、Pablo Galindo Salgado、Raymond Hettinger、Neil Schemenauer 和 Serhiy Storchaka 在 bpo-36012 中貢獻。)
減少了將引數傳遞給許多內建函式和方法的開銷。 這將某些簡單的內建函式和方法的呼叫速度提高了 20-50%。(由 Serhiy Storchaka 在 bpo-23867, bpo-35582 和 bpo-36127 中貢獻。)
LOAD_GLOBAL
指令現在使用新的“每個操作碼快取”機制。 它現在快了大約 40%。(由 Yury Selivanov 和 Inada Naoki 在 bpo-26219 中貢獻。)
構建和 C API 更改¶
預設的
sys.abiflags
變成了一個空字串:pymalloc 的m
標誌變得無用(有和沒有 pymalloc 的構建是 ABI 相容的),因此已被刪除。(由 Victor Stinner 在 bpo-36707 中貢獻。)更改示例
僅安裝
python3.8
程式,python3.8m
程式已消失。僅安裝
python3.8-config
指令碼,python3.8m-config
指令碼已消失。已從動態庫檔名的字尾中刪除了
m
標誌:標準庫中的擴充套件模組以及第三方軟體包生成和安裝的擴充套件模組,例如從 PyPI 下載的擴充套件模組。 例如,在 Linux 上,Python 3.7 字尾.cpython-37m-x86_64-linux-gnu.so
在 Python 3.8 中變為.cpython-38-x86_64-linux-gnu.so
。
已重新組織標頭檔案,以更好地分離不同型別的 API
Include/*.h
應該是可移植的公共穩定 C API。Include/cpython/*.h
應該是特定於 CPython 的不穩定 C API;公共 API,其中一些私有 API 的字首為_Py
或_PY
。Include/internal/*.h
是 CPython 特有的私有內部 C API。 此 API 沒有向後相容性保證,不應在 CPython 外部使用。 它僅用於非常特定的需求,例如必須訪問 CPython 內部而無需呼叫函式的偵錯程式和配置檔案。 此 API 現在由make install
安裝。
(由 Victor Stinner 在 bpo-35134 和 bpo-35081 中貢獻,Eric Snow 在 Python 3.7 中啟動的工作。)
一些宏已轉換為靜態行內函數:引數型別和返回型別已明確定義,它們沒有特定於宏的問題,變數具有區域性作用域。 示例
PyObject_INIT()
,PyObject_INIT_VAR()
私有函式:
_PyObject_GC_TRACK()
,_PyObject_GC_UNTRACK()
,_Py_Dealloc()
(由 Victor Stinner 在 bpo-35059 中貢獻。)
PyByteArray_Init()
和PyByteArray_Fini()
函式已被移除。自從 Python 2.7.4 和 Python 3.2.0 以來,它們就沒有任何作用,並且被排除在有限 API(穩定 ABI)之外,也沒有被文件化。(由 Victor Stinner 在 bpo-35713 中貢獻。)PyExceptionClass_Name()
的結果現在是const char *
型別,而不是char *
。(由 Serhiy Storchaka 在 bpo-33818 中貢獻。)Modules/Setup.dist
和Modules/Setup
的雙重性已被移除。之前,當更新 CPython 原始碼樹時,為了反映上游的任何更改,必須手動將Modules/Setup.dist
(在原始碼樹內)複製到Modules/Setup
(在構建樹內)。這對打包者來說只是一個小小的便利,但對於跟蹤 CPython 開發的開發者來說卻是一個頻繁的煩惱,因為忘記複製該檔案可能會導致構建失敗。現在,構建系統總是從原始碼樹內的
Modules/Setup
讀取。鼓勵想要自定義該檔案的人將他們的更改維護在 CPython 的 git 分支中,或者作為補丁檔案,就像他們對原始碼樹的任何其他更改所做的那樣。(由 Antoine Pitrou 在 bpo-32430 中貢獻。)
將 Python 數字轉換為 C 整數的函式,如
PyLong_AsLong()
,以及帶有整數轉換格式單元(如'i'
)的引數解析函式,如PyArg_ParseTuple()
,現在將使用__index__()
特殊方法(如果可用),而不是__int__()
。對於具有__int__()
方法但沒有__index__()
方法的物件(如Decimal
和Fraction
),將發出棄用警告。PyNumber_Check()
現在將為實現__index__()
的物件返回1
。PyNumber_Long()
、PyNumber_Float()
和PyFloat_AsDouble()
現在也會在可用時使用__index__()
方法。(由 Serhiy Storchaka 在 bpo-36048 和 bpo-20092 中貢獻。)堆分配的型別物件現在將在
PyObject_Init()
(及其並行宏PyObject_INIT
)中增加它們的引用計數,而不是在PyType_GenericAlloc()
中。修改例項分配或釋放的型別可能需要進行調整。(由 Eddie Elizondo 在 bpo-35810 中貢獻。)新的函式
PyCode_NewWithPosOnlyArgs()
允許建立程式碼物件,類似於PyCode_New()
,但帶有一個額外的 posonlyargcount 引數,用於指示僅位置引數的數量。(由 Pablo Galindo 在 bpo-37221 中貢獻。)Py_SetPath()
現在將sys.executable
設定為程式的完整路徑 (Py_GetProgramFullPath()
),而不是程式名稱 (Py_GetProgramName()
)。(由 Victor Stinner 在 bpo-38234 中貢獻。)
已棄用¶
distutils 的
bdist_wininst
命令現在已棄用,請改用bdist_wheel
(wheel 包)。(由 Victor Stinner 在 bpo-37481 中貢獻。)ElementTree
模組中已棄用的方法getchildren()
和getiterator()
現在發出DeprecationWarning
,而不是PendingDeprecationWarning
。它們將在 Python 3.9 中被移除。(由 Serhiy Storchaka 在 bpo-29209 中貢獻。)將不是
concurrent.futures.ThreadPoolExecutor
例項的物件傳遞給loop.set_default_executor()
已被棄用,並且將在 Python 3.9 中被禁止。(由 Elvis Pranskevichus 在 bpo-34075 中貢獻。)xml.dom.pulldom.DOMEventStream
、wsgiref.util.FileWrapper
和fileinput.FileInput
的__getitem__()
方法已被棄用。這些方法的實現一直在忽略它們的 index 引數,而是返回下一個專案。(由 Berker Peksag 在 bpo-9372 中貢獻。)
typing.NamedTuple
類已棄用_field_types
屬性,轉而使用具有相同資訊的__annotations__
屬性。(由 Raymond Hettinger 在 bpo-36320 中貢獻。)ast
類Num
、Str
、Bytes
、NameConstant
和Ellipsis
被認為是已棄用的,並且將在未來的 Python 版本中被移除。應改用Constant
。(由 Serhiy Storchaka 在 bpo-32892 中貢獻。)ast.NodeVisitor
方法visit_Num()
、visit_Str()
、visit_Bytes()
、visit_NameConstant()
和visit_Ellipsis()
現在已被棄用,並且在未來的 Python 版本中將不會被呼叫。新增visit_Constant()
方法來處理所有常量節點。(由 Serhiy Storchaka 在 bpo-36917 中貢獻。)asyncio.coroutine()
裝飾器 已被棄用,並且將在 3.10 版本中被移除。請使用async def
代替@asyncio.coroutine
。(由 Andrew Svetlov 在 bpo-36921 中貢獻。)在
asyncio
中,顯式傳遞 loop 引數已被棄用,並且將在 3.10 版本中移除,以下函式和類將受影響:asyncio.sleep()
,asyncio.gather()
,asyncio.shield()
,asyncio.wait_for()
,asyncio.wait()
,asyncio.as_completed()
,asyncio.Task
,asyncio.Lock
,asyncio.Event
,asyncio.Condition
,asyncio.Semaphore
,asyncio.BoundedSemaphore
,asyncio.Queue
,asyncio.create_subprocess_exec()
, 以及asyncio.create_subprocess_shell()
。顯式地將協程物件傳遞給
asyncio.wait()
已被棄用,並且將在 3.11 版本中移除。(由 Yury Selivanov 在 bpo-34790 中貢獻。)以下函式和方法在
gettext
模組中已被棄用:lgettext()
,ldgettext()
,lngettext()
和ldngettext()
。 它們返回編碼後的位元組,如果翻譯後的字串存在編碼問題,您可能會遇到意外的 Unicode 相關異常。 最好使用在 Python 3 中返回 Unicode 字串的替代方案。這些函式長期以來都存在問題。函式
bind_textdomain_codeset()
, 方法output_charset()
和set_output_charset()
,以及函式translation()
和install()
的 codeset 引數也被棄用,因為它們僅用於l*gettext()
函式。(由 Serhiy Storchaka 在 bpo-33710 中貢獻。)threading.Thread
的isAlive()
方法已被棄用。(由 Donghee Na 在 bpo-35283 中貢獻。)許多接受整數引數的內建和擴充套件函式現在將針對
Decimal
,Fraction
和任何其他只能透過損失轉換為整數的物件(例如,具有__int__()
方法但沒有__index__()
方法的物件)發出棄用警告。在未來版本中,它們將是錯誤。(由 Serhiy Storchaka 在 bpo-36048 中貢獻。)棄用將以下引數作為關鍵字引數傳遞:
functools.partialmethod()
,weakref.finalize()
,profile.Profile.runcall()
,cProfile.Profile.runcall()
,bdb.Bdb.runcall()
,trace.Trace.runfunc()
和curses.wrapper()
中的 func 。unittest.TestCase.addCleanup()
中的 function 。submit()
方法中concurrent.futures.ThreadPoolExecutor
和concurrent.futures.ProcessPoolExecutor
的 fn 。contextlib.ExitStack.callback()
,contextlib.AsyncExitStack.callback()
和contextlib.AsyncExitStack.push_async_callback()
中的 callback 。multiprocessing.managers.Server
和multiprocessing.managers.SharedMemoryServer
的create()
方法中的 c 和 typeid。weakref.finalize()
中的 obj 。
在未來的 Python 版本中,它們將是 僅限位置引數。(由 Serhiy Storchaka 在 bpo-36492 中貢獻。)
API 和功能移除¶
以下功能和 API 已從 Python 3.8 中移除
從 Python 3.3 開始,從
collections
匯入 ABC 已被棄用,應該從collections.abc
匯入。 從 collections 匯入的能力被標記為在 3.8 中刪除,但已推遲到 3.9。(請參閱 gh-81134。)在 Python 3.7 中已棄用的
macpath
模組已被刪除。(由 Victor Stinner 在 bpo-35471 中貢獻。)自 Python 3.3 起已棄用的函式
platform.popen()
已被刪除:請改用os.popen()
。(由 Victor Stinner 在 bpo-35345 中貢獻。)自 Python 3.3 起已棄用的函式
time.clock()
已被刪除:請改用time.perf_counter()
或time.process_time()
,具體取決於您的需求,以獲得明確定義的行為。(由 Matthias Bussonnier 在 bpo-36895 中貢獻。)為了避免對
pyvenv
指令碼所關聯的 Python 直譯器產生混淆,已移除pyvenv
指令碼,改用python3.8 -m venv
。(由 Brett Cannon 在 bpo-25427 中貢獻。)parse_qs
、parse_qsl
和escape
已從cgi
模組中移除。它們在 Python 3.2 或更早版本中已棄用。應該從urllib.parse
和html
模組匯入。filemode
函式已從tarfile
模組中移除。它未被記錄,並且自 Python 3.3 起已棄用。XMLParser
建構函式不再接受 *html* 引數。它從未生效,並且在 Python 3.4 中已棄用。所有其他引數現在都是僅關鍵字。(由 Serhiy Storchaka 在 bpo-29209 中貢獻。)移除了
XMLParser
的doctype()
方法。(由 Serhiy Storchaka 在 bpo-29209 中貢獻。)移除了“unicode_internal”編解碼器。(由 Inada Naoki 在 bpo-36297 中貢獻。)
sqlite3
模組的Cache
和Statement
物件不再向使用者公開。(由 Aviv Palivoda 在 bpo-30262 中貢獻。)fileinput.input()
和fileinput.FileInput()
的bufsize
關鍵字引數已被移除,該引數自 Python 3.6 起就被忽略並已棄用。bpo-36952(由 Matthias Bussonnier 貢獻。)Python 3.7 中已棄用的函式
sys.set_coroutine_wrapper()
和sys.get_coroutine_wrapper()
已被移除;bpo-36933(由 Matthias Bussonnier 貢獻。)
移植到 Python 3.8¶
本節列出了先前描述的更改和其他可能需要更改程式碼的錯誤修復。
Python 行為的更改¶
現在不允許在推導式和生成器表示式中使用 yield 表示式(包括
yield
和yield from
子句)(除了最左邊的for
子句中的可迭代表達式)。(由 Serhiy Storchaka 在 bpo-10544 中貢獻。)當標識檢查(
is
和is not
)與某些型別的字面量(例如字串、數字)一起使用時,編譯器現在會產生SyntaxWarning
。這些在 CPython 中通常會意外地工作,但語言規範不保證。該警告建議使用者改用相等性測試(==
和!=
)。(由 Serhiy Storchaka 在 bpo-34850 中貢獻。)CPython 直譯器在某些情況下可以吞噬異常。在 Python 3.8 中,這種情況發生的次數更少。特別是,從型別字典獲取屬性時引發的異常不再被忽略。(由 Serhiy Storchaka 在 bpo-35459 中貢獻。)
從內建型別
bool
、int
、float
、complex
和標準庫中的幾個類中移除了__str__
實現。它們現在從object
繼承__str__()
。因此,在這些類的子類中定義__repr__()
方法將影響它們的字串表示形式。(由 Serhiy Storchaka 在 bpo-36793 中貢獻。)在 AIX 上,
sys.platform
不再包含主版本號。它始終是'aix'
,而不是'aix3'
..'aix7'
。由於較舊的 Python 版本包含版本號,因此建議始終使用sys.platform.startswith('aix')
。(由 M. Felt 在 bpo-36588 中貢獻。)如果直譯器正在最終確定,則呼叫
PyEval_AcquireLock()
和PyEval_AcquireThread()
現在會終止當前執行緒,使它們與PyEval_RestoreThread()
、Py_END_ALLOW_THREADS()
和PyGILState_Ensure()
一致。如果不需要此行為,請透過檢查_Py_IsFinalizing()
或sys.is_finalizing()
來保護呼叫。(由 Joannah Nanjekye 在 bpo-36475 中貢獻。)
Python API 的更改¶
os.getcwdb()
函式現在在 Windows 上使用 UTF-8 編碼,而不是 ANSI 內碼表:有關其原理,請參閱 PEP 529。該函式在 Windows 上不再棄用。(由 Victor Stinner 在 bpo-37412 中貢獻。)subprocess.Popen
現在可以在某些情況下使用os.posix_spawn()
以獲得更好的效能。在適用於 Linux 的 Windows 子系統和 QEMU 使用者模擬上,使用os.posix_spawn()
的Popen
建構函式不再在出現諸如“缺少程式”之類的錯誤時引發異常。相反,子程序會失敗並返回非零returncode
。(由 Joannah Nanjekye 和 Victor Stinner 在 bpo-35537 中貢獻。)subprocess.Popen
的 *preexec_fn* 引數不再與子直譯器相容。在子直譯器中使用該引數現在會引發RuntimeError
。(由 Eric Snow 在 bpo-34651 中貢獻,由 Christian Heimes 在 bpo-37951 中修改。)imap.IMAP4.logout()
方法不再靜默忽略任意異常。(由 Victor Stinner 在 bpo-36348 中貢獻。)自 Python 3.3 起已棄用的函式
platform.popen()
已被刪除:請改用os.popen()
。(由 Victor Stinner 在 bpo-35345 中貢獻。)當給定多峰資料時,
statistics.mode()
函式不再引發異常。相反,它返回輸入資料中遇到的第一個眾數。(由 Raymond Hettinger 在 bpo-35892 中貢獻。)selection()
方法(屬於tkinter.ttk.Treeview
類)不再接受引數。在 Python 3.6 中,使用引數來更改選擇已被棄用。請使用專門的方法(如selection_set()
)來更改選擇。(由 Serhiy Storchaka 在 bpo-31508 中貢獻。)writexml()
、toxml()
和toprettyxml()
方法(屬於xml.dom.minidom
),以及write()
方法(屬於xml.etree
),現在會保留使用者指定的屬性順序。(由 Diego Rojas 和 Raymond Hettinger 在 bpo-34160 中貢獻。)以
'r'
標誌開啟的dbm.dumb
資料庫現在是隻讀的。dbm.dumb.open()
使用'r'
和'w'
標誌時,如果資料庫不存在,則不再建立資料庫。(由 Serhiy Storchaka 在 bpo-32749 中貢獻。)在
XMLParser
的子類中定義的doctype()
方法將不再被呼叫,並且會發出RuntimeWarning
而不是DeprecationWarning
。請在目標上定義doctype()
方法來處理 XML 文件型別宣告。(由 Serhiy Storchaka 在 bpo-29209 中貢獻。)當自定義元類在傳遞給
type.__new__
的名稱空間中沒有提供__classcell__
條目時,現在會引發RuntimeError
。在 Python 3.6–3.7 中,會發出DeprecationWarning
。(由 Serhiy Storchaka 在 bpo-23722 中貢獻。)cProfile.Profile
類現在可以用作上下文管理器。(由 Scott Sanderson 在 bpo-29235 中貢獻。)shutil.copyfile()
,shutil.copy()
,shutil.copy2()
,shutil.copytree()
和shutil.move()
使用特定於平臺的“快速複製”系統呼叫(請參閱 平臺相關的有效複製操作 部分)。Windows 上
shutil.copyfile()
的預設緩衝區大小從 16 KiB 更改為 1 MiB。PyGC_Head
結構已完全更改。所有涉及結構成員的程式碼都應重寫。(請參閱 bpo-33597。)PyInterpreterState
結構已被移至“內部”標頭檔案(特別是 Include/internal/pycore_pystate.h)。不透明的PyInterpreterState
仍然作為公共 API(和穩定的 ABI)的一部分提供。文件指出該結構的任何欄位都不是公共的,因此我們希望沒有人使用它們。但是,如果您確實依賴一個或多個這些私有欄位並且沒有其他選擇,請開啟一個 BPO 問題。我們將努力幫助您進行調整(可能包括向公共 API 新增訪問器函式)。(請參閱 bpo-35886。)mmap.flush()
方法現在在所有平臺上成功時返回None
,在出錯時引發異常。以前,其行為取決於平臺:在 Windows 上,成功時返回非零值;出錯時返回零值。在 Unix 上,成功時返回零值;出錯時引發異常。(由 Berker Peksag 在 bpo-2122 中貢獻。)xml.dom.minidom
和xml.sax
模組預設不再處理外部實體。(由 Christian Heimes 在 bpo-17239 中貢獻。)從只讀
dbm
資料庫(dbm.dumb
,dbm.gnu
或dbm.ndbm
)中刪除鍵會引發error
(dbm.dumb.error
,dbm.gnu.error
或dbm.ndbm.error
) 而不是KeyError
。(由 Xiang Zhang 在 bpo-33106 中貢獻。)簡化字面值的 AST。所有常量都將表示為
ast.Constant
例項。例項化舊類Num
、Str
、Bytes
、NameConstant
和Ellipsis
將返回一個Constant
的例項。(由 Serhiy Storchaka 在 bpo-32892 中貢獻。)Windows 上的
expanduser()
現在優先使用USERPROFILE
環境變數,並且不使用HOME
,後者通常不為常規使用者帳戶設定。(由 Anthony Sottile 在 bpo-36264 中貢獻。)異常
asyncio.CancelledError
現在繼承自BaseException
而不是Exception
,並且不再繼承自concurrent.futures.CancelledError
。(由 Yury Selivanov 在 bpo-32528 中貢獻。)現在,當使用
asyncio.Task
的例項時,函式asyncio.wait_for()
可以正確等待取消操作。 之前,當達到timeout時,它會被取消並立即返回。(由 Elvis Pranskevichus 貢獻,詳見 bpo-32751。)現在,當將 ‘socket’ 傳遞給 name 引數時,函式
asyncio.BaseTransport.get_extra_info()
會返回一個可以安全使用的套接字物件。(由 Yury Selivanov 貢獻,詳見 bpo-37027。)asyncio.BufferedProtocol
已升級為穩定 API。
現在,Windows 上擴充套件模組和透過
ctypes
載入的 DLL 的 DLL 依賴項的解析更加安全。只會在系統路徑、包含 DLL 或 PYD 檔案的目錄,以及透過add_dll_directory()
新增的目錄中搜索載入時依賴項。具體來說,不再使用PATH
和當前工作目錄,並且對它們的修改不再對正常的 DLL 解析產生任何影響。如果您的應用程式依賴這些機制,您應該檢查add_dll_directory()
,如果它存在,則在載入庫時使用它來新增您的 DLL 目錄。 請注意,Windows 7 使用者需要確保已安裝 Windows 更新 KB2533623(安裝程式也會驗證這一點)。(由 Steve Dower 貢獻,詳見 bpo-36085。)在用純 Python 實現替換 pgen 之後,與 pgen 相關的標頭檔案和函式已被刪除。(由 Pablo Galindo 貢獻,詳見 bpo-36623。)
types.CodeType
的建構函式在第二個位置(posonlyargcount)有一個新引數,以支援 PEP 570 中定義的位置引數。 第一個引數(argcount)現在表示位置引數的總數(包括僅限位置的引數)。types.CodeType
的新replace()
方法可用於使程式碼在未來保持相容性。hmac.new()
的引數digestmod
不再預設使用 MD5 摘要。
C API 中的更改¶
PyCompilerFlags
結構體獲得了一個新的 cf_feature_version 欄位。 它應該初始化為PY_MINOR_VERSION
。 該欄位預設情況下被忽略,並且當且僅當在 cf_flags 中設定了PyCF_ONLY_AST
標誌時才使用。(由 Guido van Rossum 貢獻,詳見 bpo-35766。)PyEval_ReInitThreads()
函式已從 C API 中刪除。 不應顯式呼叫它:請改用PyOS_AfterFork_Child()
。(由 Victor Stinner 貢獻,詳見 bpo-36728。)在 Unix 上,C 擴充套件程式不再連結到 libpython,除非是在 Android 和 Cygwin 上。當 Python 被嵌入時,
libpython
不得使用RTLD_LOCAL
載入,而應使用RTLD_GLOBAL
載入。 以前,使用RTLD_LOCAL
,已經無法載入未連結到libpython
的 C 擴充套件程式,例如由Modules/Setup
的*shared*
部分構建的標準庫的 C 擴充套件程式。(由 Victor Stinner 貢獻,詳見 bpo-21536。)現在,在解析或構建值時(例如,
PyArg_ParseTuple()
,Py_BuildValue()
,PyObject_CallFunction()
等)使用不帶定義PY_SSIZE_T_CLEAN
的格式的#
變體,會引發DeprecationWarning
。它將在 3.10 或 4.0 中刪除。有關詳細資訊,請閱讀 解析引數和構建值。(由 Inada Naoki 貢獻,詳見 bpo-36381。)堆分配型別(例如使用
PyType_FromSpec()
建立的型別)的例項保留對其型別物件的引用。 增加這些型別物件的引用計數已從PyType_GenericAlloc()
移至更底層的函式,PyObject_Init()
和PyObject_INIT()
。 這使得透過PyType_FromSpec()
建立的型別在託管程式碼中的行為與其他類類似。靜態分配型別 不受影響。
在絕大多數情況下,不應有任何副作用。但是,在分配例項後手動增加引用計數(可能是為了解決該錯誤)的型別現在可能會變為永生。為了避免這種情況,這些類需要在例項釋放期間呼叫 Py_DECREF 來釋放型別物件。
要將這些型別正確移植到 3.8,請應用以下更改
刪除分配例項後型別物件的
Py_INCREF
(如果有)。這可能會在呼叫PyObject_New
,PyObject_NewVar
,PyObject_GC_New()
,PyObject_GC_NewVar()
或任何使用PyObject_Init()
或PyObject_INIT()
的其他自定義分配器之後發生。示例
static foo_struct * foo_new(PyObject *type) { foo_struct *foo = PyObject_GC_New(foo_struct, (PyTypeObject *) type); if (foo == NULL) return NULL; #if PY_VERSION_HEX < 0x03080000 // Workaround for Python issue 35810; no longer necessary in Python 3.8 PY_INCREF(type) #endif return foo; }
確保堆分配型別的所有自定義
tp_dealloc
函式都會減少型別的引用計數。示例
static void foo_dealloc(foo_struct *instance) { PyObject *type = Py_TYPE(instance); PyObject_GC_Del(instance); #if PY_VERSION_HEX >= 0x03080000 // This was not needed before Python 3.8 (Python issue 35810) Py_DECREF(type); #endif }
(由 Eddie Elizondo 貢獻,詳見 bpo-35810。)
Py_DEPRECATED()
宏已為 MSVC 實現。 現在,該宏必須放在符號名稱之前。示例
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
(由 Zackery Spytz 貢獻,詳見 bpo-33407。)
直譯器不再假裝支援跨功能版本的擴充套件型別的二進位制相容性。第三方擴充套件模組匯出的
PyTypeObject
應該具有當前 Python 版本中期望的所有插槽,包括tp_finalize
(讀取tp_finalize
之前不再檢查Py_TPFLAGS_HAVE_FINALIZE
)。(由 Antoine Pitrou 貢獻,詳見 bpo-32388。)
現在,函式
PyNode_AddChild()
和PyParser_AddToken()
接受兩個額外的int
引數 end_lineno 和 end_col_offset。不再在常規 Windows 發行版中包含
libpython38.a
檔案,以允許 MinGW 工具直接連結到python38.dll
。如果您需要此檔案,可以使用gendef
和dlltool
工具生成它,這些工具是 MinGW binutils 包的一部分gendef - python38.dll > tmp.def dlltool --dllname python38.dll --def tmp.def --output-lib libpython38.a
已安裝的
pythonXY.dll
的位置將取決於安裝選項以及 Windows 的版本和語言。有關更多資訊,請參見 在 Windows 上使用 Python。生成的庫應與pythonXY.lib
放在同一目錄中,該目錄通常是 Python 安裝下的libs
目錄。(由 Steve Dower 貢獻,詳見 bpo-37351。)
CPython 位元組碼更改¶
直譯器迴圈已得到簡化,透過將展開程式碼塊堆疊的邏輯移至編譯器中。現在,編譯器會發出顯式指令來調整值堆疊,併為
break
、continue
和return
呼叫清理程式碼。移除了操作碼
BREAK_LOOP
、CONTINUE_LOOP
、SETUP_LOOP
和SETUP_EXCEPT
。添加了新的操作碼ROT_FOUR
、BEGIN_FINALLY
、CALL_FINALLY
和POP_FINALLY
。更改了END_FINALLY
和WITH_CLEANUP_START
的行為。(由 Mark Shannon、Antoine Pitrou 和 Serhiy Storchaka 在 bpo-17611 中貢獻。)
添加了新的操作碼
END_ASYNC_FOR
,用於處理在async for
迴圈中等待下一個專案時引發的異常。(由 Serhiy Storchaka 在 bpo-33041 中貢獻。)現在,
MAP_ADD
期望值作為堆疊中的第一個元素,鍵作為第二個元素。做出此更改是為了確保在字典推導式中始終先評估鍵,然後評估值,正如 PEP 572 所建議的那樣。(由 Jörn Heissler 在 bpo-35224 中貢獻。)
演示和工具¶
添加了一個基準測試指令碼,用於測量訪問各種變數的方式所需的時間:Tools/scripts/var_access_benchmark.py
。(由 Raymond Hettinger 在 bpo-35884 中貢獻。)
以下是自 Python 3.3 以來的效能改進摘要
Python version 3.3 3.4 3.5 3.6 3.7 3.8
-------------- --- --- --- --- --- ---
Variable and attribute read access:
read_local 4.0 7.1 7.1 5.4 5.1 3.9
read_nonlocal 5.3 7.1 8.1 5.8 5.4 4.4
read_global 13.3 15.5 19.0 14.3 13.6 7.6
read_builtin 20.0 21.1 21.6 18.5 19.0 7.5
read_classvar_from_class 20.5 25.6 26.5 20.7 19.5 18.4
read_classvar_from_instance 18.5 22.8 23.5 18.8 17.1 16.4
read_instancevar 26.8 32.4 33.1 28.0 26.3 25.4
read_instancevar_slots 23.7 27.8 31.3 20.8 20.8 20.2
read_namedtuple 68.5 73.8 57.5 45.0 46.8 18.4
read_boundmethod 29.8 37.6 37.9 29.6 26.9 27.7
Variable and attribute write access:
write_local 4.6 8.7 9.3 5.5 5.3 4.3
write_nonlocal 7.3 10.5 11.1 5.6 5.5 4.7
write_global 15.9 19.7 21.2 18.0 18.0 15.8
write_classvar 81.9 92.9 96.0 104.6 102.1 39.2
write_instancevar 36.4 44.6 45.8 40.0 38.9 35.5
write_instancevar_slots 28.7 35.6 36.1 27.3 26.6 25.7
Data structure read access:
read_list 19.2 24.2 24.5 20.8 20.8 19.0
read_deque 19.9 24.7 25.5 20.2 20.6 19.8
read_dict 19.7 24.3 25.7 22.3 23.0 21.0
read_strdict 17.9 22.6 24.3 19.5 21.2 18.9
Data structure write access:
write_list 21.2 27.1 28.5 22.5 21.6 20.0
write_deque 23.8 28.7 30.1 22.7 21.8 23.5
write_dict 25.9 31.4 33.3 29.3 29.2 24.7
write_strdict 22.9 28.4 29.9 27.5 25.2 23.1
Stack (or queue) operations:
list_append_pop 144.2 93.4 112.7 75.4 74.2 50.8
deque_append_pop 30.4 43.5 57.0 49.4 49.2 42.5
deque_append_popleft 30.8 43.7 57.3 49.7 49.7 42.8
Timing loop:
loop_overhead 0.3 0.5 0.6 0.4 0.3 0.3
這些基準測試是在 Intel® Core™ i7-4960HQ 處理器上測量的,該處理器執行的是在 python.org 上找到的 macOS 64 位版本。基準測試指令碼以納秒為單位顯示時間。
Python 3.8.1 中的重大更改¶
由於存在重大的安全問題,不再支援 asyncio.loop.create_datagram_endpoint()
的 *reuse_address* 引數。這是因為 UDP 中套接字選項 SO_REUSEADDR
的行為。有關更多詳細資訊,請參閱 loop.create_datagram_endpoint()
的文件。(由 Kyle Stanley、Antoine Pitrou 和 Yury Selivanov 在 bpo-37228 中貢獻。)
Python 3.8.2 中的重大更改¶
修復了 shutil.copytree()
的 ignore
回撥中的一個迴歸錯誤。引數型別現在再次為 str 和 List[str]。(由 Manuel Barkhau 和 Giampaolo Rodola 在 gh-83571 中貢獻。)
Python 3.8.3 中的重大更改¶
更新了 __future__
模組中 future 標誌的常量值,以防止與編譯器標誌發生衝突。以前,PyCF_ALLOW_TOP_LEVEL_AWAIT
與 CO_FUTURE_DIVISION
衝突。(由 Batuhan Taskaya 在 gh-83743 中貢獻。)
Python 3.8.8 中的重大更改¶
早期的 Python 版本允許在 urllib.parse.parse_qs()
和 urllib.parse.parse_qsl()
中使用 ;
和 &
作為查詢引數分隔符。出於安全考慮,併為了符合較新的 W3C 建議,此行為已更改為僅允許單個分隔符鍵,預設使用 &
。此更改還會影響 cgi.parse()
和 cgi.parse_multipart()
,因為它們在內部使用了受影響的函式。有關更多詳細資訊,請參閱它們各自的文件。(由 Adam Goldschmidt、Senthil Kumaran 和 Ken Jin 在 bpo-42967 中貢獻。)
Python 3.8.9 中的重大更改¶
一個安全修復程式更改了 ftplib.FTP
的行為,使其在設定被動資料通道時不信任遠端伺服器傳送的 IPv4 地址。我們改為重用 ftp 伺服器的 IP 地址。對於需要舊行為的異常程式碼,請將您的 FTP 例項上的 trust_server_pasv_ipv4_address
屬性設定為 True
。(請參閱 gh-87451)
Python 3.8.10 中的重大更改¶
macOS 11.0 (Big Sur) 和 Apple Silicon Mac 支援¶
從 3.8.10 開始,Python 現在支援在 macOS 11 (Big Sur) 和基於 ARM64
架構的 Apple Silicon Mac 上構建和執行。現在可以使用新的通用構建變體 universal2
,以在一個可執行檔案集中本地支援 ARM64
和 Intel 64
。請注意,此從 Python 3.9 的向後移植中不包含對“弱連結”的支援,即構建面向較新 macOS 版本的二進位制檔案,這些二進位制檔案也將在較舊版本上正確執行,方法是在執行時測試缺失的功能;要支援一系列 macOS 版本,請繼續以該範圍中最舊的版本為目標並在此版本上進行構建。
(最初由 Ronald Oussoren 和 Lawrence D’Anna 在 gh-85272 中貢獻,由 FX Coudert 和 Eli Rykoff 進行修復,並由 Maxime Bélanger 和 Ned Deily 向後移植到 3.8)
Python 3.8.10 中的重大更改¶
urllib.parse¶
URL 的某些部分中存在換行符或製表符會導致某些形式的攻擊。根據更新 RFC 3986 的 WHATWG 規範,urllib.parse
中的解析器會從 URL 中刪除 ASCII 換行符 \n
、 \r
和製表符 \t
,從而防止此類攻擊。刪除的字元由新的模組級別變數 urllib.parse._UNSAFE_URL_BYTES_TO_REMOVE
控制。(請參閱 bpo-43882)
Python 3.8.12 中的重大更改¶
Python API 中的更改¶
從 Python 3.8.12 開始,ipaddress
模組不再接受 IPv4 地址字串中的任何前導零。前導零具有歧義,並且會被某些庫解釋為八進位制表示法。例如,舊函式 socket.inet_aton()
將前導零視為八進位制表示法。glibc 實現的現代 inet_pton()
不接受任何前導零。
(最初由 Christian Heimes 在 bpo-36384 中貢獻,並由 Achraf Merzouki 反向移植到 3.8。)
3.8.14 中的重要安全特性¶
在 2(二進位制)、4、8(八進位制)、16(十六進位制)或 32 之外的進位制(例如 10 進位制)中,int
和 str
之間的轉換,如果字串形式的位數超過限制,現在會引發 ValueError
,以避免因演算法複雜度而可能造成的拒絕服務攻擊。這是對 CVE 2020-10735 的緩解措施。可以透過環境變數、命令列標誌或 sys
API 來配置或停用此限制。請參閱 整數字符串轉換長度限制 文件。預設限制是字串形式的 4300 位數字。
3.8.17 中的重要更改¶
tarfile¶
tarfile
中的提取方法和shutil.unpack_archive()
有一個新的 filter 引數,該引數允許限制 tar 的特性,這些特性可能會令人驚訝或危險,例如在目標目錄之外建立檔案。有關詳細資訊,請參閱 提取過濾器。在 Python 3.12 中,如果不使用 filter 引數,將顯示DeprecationWarning
。在 Python 3.14 中,預設值將切換為'data'
。(由 Petr Viktorin 在 PEP 706 中貢獻。)