- 編者 Raymond Hettinger
本文解釋了 Python 3.8 相比 3.7 的新增特性睬关。 完整的詳情可參閱 更新日志。
Python 3.8已于2019年10月14日發(fā)布。
新的特性?
賦值表達(dá)式
新增的語法 :=
可在表達(dá)式內(nèi)部為變量賦值厢漩。 它被昵稱為“海象運(yùn)算符”因?yàn)樗芟袷?海象的眼睛和長牙待错。
在這個(gè)示例中,賦值表達(dá)式可以避免調(diào)用 len()
兩次:
if (n := len(a)) > 10:
print(f"List is too long ({n} elements, expected <= 10)")
類似的益處還可出現(xiàn)在正則表達(dá)式匹配中需要使用兩次匹配對(duì)象的情況中会钝,一次檢測(cè)用于匹配是否發(fā)生伐蒋,另一次用于提取子分組:
discount = 0.0
if (mo := re.search(r'(\d+)% discount', advertisement)):
discount = float(mo.group(1)) / 100.0
此運(yùn)算符也適用于配合 while 循環(huán)計(jì)算一個(gè)值來檢測(cè)循環(huán)是否終止,而同一個(gè)值又在循環(huán)體中再次被使用的情況:
# Loop over fixed length blocks
while (block := f.read(256)) != '':
process(block)
另一個(gè)值得介紹的用例出現(xiàn)于列表推導(dǎo)式中迁酸,在篩選條件中計(jì)算一個(gè)值先鱼,而同一個(gè)值又在表達(dá)式中需要被使用:
[clean_name.title() for name in names
if (clean_name := normalize('NFC', name)) in allowed_names]
請(qǐng)盡量將海象運(yùn)算符的使用限制在清晰的場(chǎng)合中,以降低復(fù)雜性并提升可讀性奸鬓。
請(qǐng)參閱 PEP 572 了解詳情焙畔。
(由 Morehouse 在 bpo-35224 中貢獻(xiàn)。)
僅限位置形參
新增了一個(gè)函數(shù)形參語法 /
用來指明某些函數(shù)形參必須使用僅限位置而非關(guān)鍵字參數(shù)的形式串远。 這種標(biāo)記語法與通過 help()
所顯示的使用 Larry Hastings 的 Argument Clinic 工具標(biāo)記的 C 函數(shù)相同宏多。
在下面的例子中,形參 a 和 b 為僅限位置形參澡罚,c 或 d 可以是位置形參或關(guān)鍵字形參伸但,而 e 或 f 要求為關(guān)鍵字形參:
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
以下均為合法的調(diào)用:
f(10, 20, 30, d=40, e=50, f=60)
但是,以下均為不合法的調(diào)用:
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
這種標(biāo)記形式的一個(gè)用例是它允許純 Python 函數(shù)完整模擬現(xiàn)有的用 C 代碼編寫的函數(shù)的行為留搔。 例如砌烁,內(nèi)置的 pow()
函數(shù)不接受關(guān)鍵字參數(shù):
def pow(x, y, z=None, /):
"Emulate the built in pow() function"
r = x ** y
return r if z is None else r%z
另一個(gè)用例是在不需要形參名稱時(shí)排除關(guān)鍵字參數(shù)。 例如催式,內(nèi)置的 len()
函數(shù)的簽名為 len(obj, /)
函喉。 這可以排除如下這種笨拙的調(diào)用形式:
len(obj='hello') # The "obj" keyword argument impairs readability
另一個(gè)益處是將形參標(biāo)記為僅限位置形參將允許在未來修改形參名而不會(huì)破壞客戶的代碼。 例如荣月,在 statistics
模塊中管呵,形參名 dist 在未來可能被修改。 這使得以下函數(shù)描述成為可能:
def quantiles(dist, /, *, n=4, method='exclusive')
...
由于在 /
左側(cè)的形參不會(huì)被公開為可用關(guān)鍵字哺窄,其他形參名仍可在 **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}
這極大地簡(jiǎn)化了需要接受任意關(guān)鍵字參數(shù)的函數(shù)和方法的實(shí)現(xiàn)捐下。 例如账锹,以下是一段摘自 collections
模塊的代碼:
class Counter(dict):
def __init__(self, iterable=None, /, **kwds):
# Note "iterable" is a possible keyword argument
用于已編譯字節(jié)碼文件的并行文件系統(tǒng)緩存
新增的 PYTHONPYCACHEPREFIX
設(shè)置 (也可使用 -X
pycache_prefix
) 可將隱式的字節(jié)碼緩存配置為使用單獨(dú)的并行文件系統(tǒng)樹,而不是默認(rèn)的每個(gè)源代碼目錄下的 __pycache__
子目錄坷襟。
緩存的位置會(huì)在 sys.pycache_prefix
中報(bào)告 (None
表示默認(rèn)位置即 __pycache__
子目錄)奸柬。
(由 Carl Meyer 在 bpo-33499 中貢獻(xiàn)。)
調(diào)試構(gòu)建使用與發(fā)布構(gòu)建相同的 ABI
Python 現(xiàn)在不論是以發(fā)布模式還是調(diào)試模式進(jìn)行構(gòu)建都將使用相同的 ABI婴程。 在 Unix 上廓奕,當(dāng) Python 以調(diào)試模式構(gòu)建時(shí),現(xiàn)在將可以加載以發(fā)布模式構(gòu)建的 C 擴(kuò)展和使用穩(wěn)定版 ABI 構(gòu)建的 C 擴(kuò)展档叔。
發(fā)布構(gòu)建和調(diào)試構(gòu)建現(xiàn)在都是 ABI 兼容的:定義 Py_DEBUG
宏不會(huì)再啟用 Py_TRACE_REFS
宏桌粉,它引入了唯一的 ABI 不兼容性。 Py_TRACE_REFS
宏添加了 sys.getobjects()
函數(shù)和 PYTHONDUMPREFS
環(huán)境變量衙四,它可以使用新的 ./configure --with-trace-refs
構(gòu)建選項(xiàng)來設(shè)置铃肯。 (由 Victor Stinner 在 bpo-36465 中貢獻(xiàn)。)
在 Unix 上传蹈,C 擴(kuò)展不會(huì)再被鏈接到 libpython押逼,但 Android 和 Cygwin 例外。 現(xiàn)在靜態(tài)鏈接的 Python 將可以加載使用共享庫 Python 構(gòu)建的 C 擴(kuò)展惦界。 (由 Victor Stinner 在 bpo-21536 中貢獻(xiàn)挑格。)
在 Unix 上,當(dāng) Python 以調(diào)試模式構(gòu)建時(shí)表锻,導(dǎo)入操作現(xiàn)在也會(huì)查找在發(fā)布模式下編譯的 C 擴(kuò)展以及使用穩(wěn)定版 ABI 編譯的 C 擴(kuò)展。 (由 Victor Stinner 在 bpo-36722 中貢獻(xiàn)乞娄。)
要將 Python 嵌入到一個(gè)應(yīng)用中瞬逊,必須將新增的 --embed
選項(xiàng)傳給 python3-config --libs --embed
以獲得 -lpython3.8
(將應(yīng)用鏈接到 libpython)。 要同時(shí)支持 3.8 和舊版本仪或,請(qǐng)先嘗試 python3-config --libs --embed
并在此命令失敗時(shí)回退到 python3-config --libs
(即不帶 --embed
)确镊。
增加一個(gè) pkg-config python-3.8-embed
模塊用來將 Python 嵌入到一個(gè)應(yīng)用中: pkg-config python-3.8-embed --libs
包含 -lpython3.8
。 要同時(shí)支持 3.8 和舊版本范删,請(qǐng)先嘗試 pkg-config python-X.Y-embed --libs
并在此命令失敗時(shí)回退到 pkg-config python-X.Y --libs
(即不帶 --embed
) (請(qǐng)將 X.Y
替換為 Python 版本號(hào))蕾域。
另一方面,pkg-config python3.8 --libs
不再包含 -lpython3.8
到旦。 C 擴(kuò)展不可被鏈接到 libpython (但 Android 和 Cygwin 例外旨巷,這兩者的情況由腳本處理);此改變是故意被設(shè)為向下不兼容的添忘。 (由 Victor Stinner 在 bpo-36721 中貢獻(xiàn)采呐。)
f-字符串支持 =
用于自動(dòng)記錄表達(dá)式和調(diào)試文檔
增加 =
說明符用于 f-string。 形式為 f'{expr=}'
的 f-字符串將擴(kuò)展表示為表達(dá)式文本搁骑,加一個(gè)等于號(hào)斧吐,再加表達(dá)式的求值結(jié)果又固。 例如:
>>> user = 'eric_idle'
>>> member_since = date(1975, 7, 31)
>>> f'{user=} {member_since=}'
"user='eric_idle' member_since=datetime.date(1975, 7, 31)"
通常的 f-字符串格式說明符 允許更細(xì)致地控制所要顯示的表達(dá)式結(jié)果:
>>>
>>> delta = date.today() - member_since
>>> f'{user=!s} {delta.days=:,d}'
'user=eric_idle delta.days=16,075'
=
說明符將輸出整個(gè)表達(dá)式,以便詳細(xì)演示計(jì)算過程:
>>>
>>> print(f'{theta=} {cos(radians(theta))=:.3f}')
theta=30 cos(radians(theta))=0.866
(由 Eric V. Smith 和 Larry Hastings 在 bpo-36817 中貢獻(xiàn)煤率。)
PEP 578: Python 運(yùn)行時(shí)審核鉤子
此 PEP 添加了審核鉤子和已驗(yàn)證開放鉤子仰冠。 兩者在 Python 與本機(jī)代碼中均可用。允許以純 Python 代碼編寫的應(yīng)用和框架利用額外的通知蝶糯,同時(shí)允許嵌入開發(fā)人員或系統(tǒng)管理員部署始終啟用審核的 Python 版本洋只。
請(qǐng)參閱 PEP 578 了解詳情。
PEP 587: Python 初始化配置
PEP 587 增加了一個(gè)新的 C API 用來配置 Python 初始化裳涛,提供對(duì)整個(gè)配置過程的更細(xì)致控制以及更好的錯(cuò)誤報(bào)告木张。
新的結(jié)構(gòu):
新的函數(shù):
PyConfig_Clear()
PyConfig_InitIsolatedConfig()
PyConfig_InitPythonConfig()
PyConfig_Read()
PyConfig_SetArgv()
PyConfig_SetBytesArgv()
PyConfig_SetBytesString()
PyConfig_SetString()
PyPreConfig_InitIsolatedConfig()
PyPreConfig_InitPythonConfig()
PyStatus_Error()
PyStatus_Exception()
PyStatus_Exit()
PyStatus_IsError()
PyStatus_IsExit()
PyStatus_NoMemory()
PyStatus_Ok()
PyWideStringList_Append()
PyWideStringList_Insert()
Py_BytesMain()
Py_ExitStatusException()
Py_InitializeFromConfig()
Py_PreInitialize()
Py_PreInitializeFromArgs()
Py_PreInitializeFromBytesArgs()
Py_RunMain()
此 PEP 還為這些內(nèi)部結(jié)構(gòu)添加了 _PyRuntimeState.preconfig
(PyPreConfig
類型) 和 PyInterpreterState.config
(PyConfig
類型) 字段。 PyInterpreterState.config
成為新的引用配置端三,替代全局配置變量和其他私有變量舷礼。
請(qǐng)參閱 Python 初始化配置 獲取詳細(xì)文檔。
請(qǐng)參閱 PEP 587 了解詳情郊闯。
(由 Victor Stinner 在 bpo-36763 中貢獻(xiàn)妻献。)
Vectorcall: 用于 CPython 的快速調(diào)用協(xié)議
添加 "vectorcall" 協(xié)議到 Python/C API。 它的目標(biāo)是對(duì)已被應(yīng)用于許多類的現(xiàn)有優(yōu)化進(jìn)行正式化团赁。 任何實(shí)現(xiàn)可調(diào)用對(duì)象的擴(kuò)展類型均可使用此協(xié)議育拨。
此特性目前為暫定狀態(tài),計(jì)劃在 Python 3.9 將其完全公開欢摄。
請(qǐng)參閱 PEP 590 了解詳情熬丧。
(由 Jeroen Demeyer 和 Mark Shannon 在 bpo-36974 中貢獻(xiàn)。)
具有外部數(shù)據(jù)緩沖區(qū)的 pickle 協(xié)議 5
當(dāng)使用 pickle
在 Python 進(jìn)程間傳輸大量數(shù)據(jù)以充分發(fā)揮多核或多機(jī)處理的優(yōu)勢(shì)時(shí)怀挠,非常重要一點(diǎn)是通過減少內(nèi)存拷貝來優(yōu)化傳輸效率析蝴,并可能應(yīng)用一些定制技巧例如針對(duì)特定數(shù)據(jù)的壓縮。
pickle
協(xié)議 5 引入了對(duì)于外部緩沖區(qū)的支持绿淋,這樣 PEP 3118 兼容的數(shù)據(jù)可以與主 pickle 流分開進(jìn)行傳輸闷畸,這是由通信層來確定的。