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中貢獻。)
其他語言更改¶
由於實現問題,
continue
語句在finally
子句中是非法的。在 Python 3.8 中,此限制被解除。(由 Serhiy Storchaka 在bpo-32489中貢獻。)bool
、int
和fractions.Fraction
型別現在擁有as_integer_ratio()
方法,與float
和decimal.Decimal
中發現的類似。此次小的 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中貢獻。)
Dict 和 dictviews 現在可以使用
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__()
方法現在可以返回一個包含兩到六個元素的元組。以前,限制是五個。新的可選第六個元素是一個可呼叫物件,其簽名是(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中貢獻。)
增加了對 Happy Eyeballs 到 asyncio.loop.create_connection()
的支援。為了指定行為,添加了兩個新引數:*happy_eyeballs_delay* 和 *interleave*。Happy Eyeballs 演算法透過嘗試同時使用 IPv4 和 IPv6 進行連線來提高支援它們的應用程式的響應能力。(由 twisteroid ambassador 在bpo-33530中貢獻。)
內建函式¶
compile()
內建函式已得到改進,可接受 ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
標誌。透過傳遞此新標誌,compile()
將允許頂層 await
、async for
和 async with
結構,這些結構通常被認為是無效語法。然後可以返回標有 CO_COROUTINE
標誌的非同步程式碼物件。(由 Matthias Bussonnier 在bpo-34616中貢獻)
collections¶
collections.namedtuple()
的 _asdict()
方法現在返回一個 dict
而不是 collections.OrderedDict
。這之所以有效,是因為自 Python 3.7 以來,常規字典保證了順序。如果需要 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中貢獻。)
現在使用 OS 本機編碼在 Python 字串和 Tcl 物件之間進行轉換。這使得 IDLE 可以處理表情符號和其他非 BMP 字元。這些字元可以顯示或複製貼上到剪貼簿。從 Tcl 轉換為 Python 再轉換回 Python 現在永遠不會失敗。(許多人為此努力了八年,但 Serhiy Storchaka 最終在bpo-13153中解決了這個問題。)
3.8.1 中的新特性
添加了關閉游標閃爍的選項。(由 Zackery Spytz 在bpo-4603中貢獻。)
Esc 鍵現在關閉 IDLE 補全視窗。(由 Johnny Najera 在bpo-38944中貢獻。)
上述更改已回溯到 3.7 維護版本。
將關鍵字新增到模組名稱補全列表。(由 Terry J. Reedy 在bpo-37765中貢獻。)
inspect¶
inspect.getdoc()
函式現在可以為 __slots__
查詢文件字串,如果該屬性是 dict
,其中值是文件字串。這提供了與我們已經擁有的 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
) 和除錯構建中,io.IOBase
終結器現在會記錄異常,如果 close()
方法失敗。在釋出構建中,異常預設會被靜默忽略。(由 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 Notebook 更新、試驗或教授各種日誌記錄配置選項變得困難。
(由 Raymond Hettinger 建議,由 Donghee Na 實現,由 Vinay Sajip 審查,在bpo-33897中。)
math¶
添加了新函式 math.dist()
,用於計算兩點之間的歐幾里得距離。(由 Raymond Hettinger 在bpo-33089中貢獻。)
擴充套件了 math.hypot()
函式以處理多個維度。以前,它只支援二維情況。(由 Raymond Hettinger 在bpo-33089中貢獻。)
添加了新函式 math.prod()
,作為 sum()
的類似函式,返回“起始”值(預設: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()
不再接受非整數類的引數。(由 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()
一樣開啟。在所有情況下,os.stat_result.st_mode
將只為符號連結設定 S_IFLNK
,而不為其他型別的重新解析點設定。要識別其他型別的重新解析點,請檢查新的 os.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()
方法來重寫函式和類的 pickle 邏輯。(由 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 中貢獻。)
shutil.rmtree()
在 Windows 上現在會直接刪除目錄連線點,而不會先遞迴刪除其內容。(由 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 中貢獻。)
時間¶
為 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']: ...
“最終”變數、函式、方法和類。參見 PEP 591、
typing.Final
和typing.final()
。final 修飾符指示靜態型別檢查器限制子類化、重寫或重新賦值。pi: Final[float] = 3.1415926536
協議定義。參見 PEP 544、
typing.Protocol
和typing.runtime_checkable()
。像typing.SupportsInt
這樣的簡單抽象基類現在是Protocol
子類。新的協議類
typing.SupportsIndex
。新的函式
typing.get_origin()
和typing.get_args()
。
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
模組提供了一個新函式 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 為假;
未設定 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
模組中的預設協議現在是協議 4,該協議首次在 Python 3.4 中引入。與 Python 3.0 中提供的協議 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 中貢獻。)__getitem__()
方法在xml.dom.pulldom.DOMEventStream
,wsgiref.util.FileWrapper
和fileinput.FileInput
中已被棄用。這些方法的實現一直忽略它們的 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
decorator 已棄用,並將在 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()
、方法NullTranslations.output_charset()
和NullTranslations.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。在
concurrent.futures.ThreadPoolExecutor
和concurrent.futures.ProcessPoolExecutor
的submit()
方法中的 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 中貢獻。)函式
platform.popen()
已移除,自 Python 3.3 起已被棄用:請改用os.popen()
。(由 Victor Stinner 在 bpo-35345 中貢獻。)函式
time.clock()
已被移除,自 Python 3.3 起已被棄用:請根據您的要求改用time.perf_counter()
或time.process_time()
,以獲得明確定義的行為。(由 Matthias Bussonnier 在 bpo-36895 中貢獻。)已移除
pyvenv
指令碼,轉而使用python3.8 -m venv
,以幫助消除關於pyvenv
指令碼與哪個 Python 直譯器繫結的困惑。(由 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¶
本節列出了前面描述過的變更以及其他可能需要修改程式碼的 bug 修復。
Python 行為的變更¶
生成器表示式和推導式(除了最左側
for
子句中的可迭代表達式)現在禁止使用 yield 表示式(包括yield
和yield from
子句)。(由 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 的變化¶
在 Windows 上,
os.getcwdb()
函式現在使用 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 中修改。)imaplib.IMAP4.logout()
方法不再默默忽略任意異常。(由 Victor Stinner 在 bpo-36348 中貢獻。)函式
platform.popen()
已移除,自 Python 3.3 起已被棄用:請改用os.popen()
。(由 Victor Stinner 在 bpo-35345 中貢獻。)當給定多峰資料時,
statistics.mode()
函式不再引發異常。相反,它返回輸入資料中遇到的第一個眾數。(由 Raymond Hettinger 在 bpo-35892 中貢獻。)tkinter.ttk.Treeview
類的selection()
方法不再接受引數。在 Python 3.6 中,使用帶引數的方法更改選擇已被棄用。請使用專門的方法,例如selection_set()
來更改選擇。(由 Serhiy Storchaka 在 bpo-31508 中貢獻。)xml.dom.minidom
的writexml()
、toxml()
和toprettyxml()
方法以及xml.etree.ElementTree
的write()
方法現在會保留使用者指定的屬性順序。(由 Diego Rojas 和 Raymond Hettinger 在 bpo-34160 中貢獻。)用標誌
'r'
開啟的dbm.dumb
資料庫現在是隻讀的。用標誌'r'
和'w'
呼叫dbm.dumb.open()
如果資料庫不存在將不再建立它。(由 Serhiy Storchaka 在 bpo-32749 中貢獻。)在
XMLParser
的子類中定義的doctype()
方法將不再被呼叫,並且會發出RuntimeWarning
而不是DeprecationWarning
。要處理 XML doctype 宣告,請在目標上定義doctype()
方法。(由 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 中貢獻。)當向 name 引數傳遞“socket”時,
asyncio.BaseTransport.get_extra_info()
函式現在返回一個可安全使用的 socket 物件。(由 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 中貢獻。)在 pgen 被純 Python 實現取代後,相關的標頭檔案和函式已被刪除。(由 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 中貢獻。)在未定義
PY_SSIZE_T_CLEAN
的情況下,在解析或構建值時使用格式的#
變體(例如PyArg_ParseTuple()
、Py_BuildValue()
、PyObject_CallFunction()
等)現在會引發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
(不再檢查Py_TPFLAGS_HAVE_FINALIZE
,然後再讀取tp_finalize
)。(由 Antoine Pitrou 在 bpo-32388 中貢獻。)
函式
PyNode_AddChild()
和PyParser_AddToken()
現在接受兩個額外的int
引數 end_lineno 和 end_col_offset。libpython38.a
檔案(允許 MinGW 工具直接連結到python38.dll
)不再包含在常規 Windows 分發中。如果需要此檔案,可以使用 MinGW binutils 包中的gendef
和dlltool
工具生成。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
這些基準測試是在執行 macOS 64 位構建的 Intel® Core™ i7-4960HQ 處理器 上測量的,可在 python.org 找到。基準指令碼以納秒顯示計時。
Python 3.8.1 的顯著變化¶
由於重大的安全問題,不再支援 asyncio.loop.create_datagram_endpoint()
的 reuse_address 引數。這是由於 SO_REUSEADDR
套接字選項在 UDP 中的行為。有關更多詳細資訊,請參見 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__
模組中未來標誌的常量值已更新。以前 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) 和 Apple Silicon Mac (基於 ARM64
架構) 上構建和執行。現在提供了一個新的通用構建變體 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()
將前導零視為八進位制表示法。現代 inet_pton()
的 glibc 實現不接受任何前導零。
(最初由 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 中貢獻。)