Python 3.8 一周后發(fā)布,這幾個(gè)特性值得關(guān)注

文 | EarlGrey
推薦 | 編程派公眾號(hào)(ID:codingpy)
10月1日,Python 3.8rc1 發(fā)布,如果沒(méi)有意外的話 3.8 將于 10 月 14 日正式發(fā)布。新版本的變化有很多,但是我覺(jué)得可能最常被用到的,是下面這兩個(gè)新特性:海象運(yùn)算符和僅位置參數(shù)。
海象運(yùn)算符 :=
海象運(yùn)算符是 3.8 版本中最引人矚目的新特性,因其 := 外觀而被稱為海象運(yùn)算符(walrus operator)。引入該運(yùn)算符的是 PEP 572,而也正是由于 PEP 572 被接受過(guò)程中的一些不愉快,導(dǎo)致了 Guido van Rossum 因此辭去了 BDFL 的職位。
有了這個(gè)運(yùn)算之后,我們可以在 if 或 while 語(yǔ)句中使用 := 為變量賦值,其目的也是為了簡(jiǎn)化多模式匹配和非可迭代對(duì)象的循環(huán)等問(wèn)題。
比如說(shuō),多模式匹配的寫法會(huì)從:
m = re.match(p1, line)if m:return m.group(1)else:m = re.match(p2, line)if m:return m.group(2)else:m = re.match(p3, line)...
變成:
if m := re.match(p1, line):return m.group(1)elif m := re.match(p2, line):return m.group(2)elif m := re.match(p3, line):...
而針對(duì)非可迭代對(duì)象的循環(huán),也可以從:
ent = obj.next_entry()while ent:... # process entent = obj.next_entry()
變成這樣:
while ent := obj.next_entry():... # process ent
這可以讓程序員更清晰地表達(dá)自己的意圖。這個(gè)功能其實(shí)是許多其他語(yǔ)言已經(jīng)具備的,但是Python中已經(jīng)缺失近30年。
相較于由它給Python社區(qū)帶來(lái)的變動(dòng),這個(gè)特性本身帶來(lái)的變化就不那么明顯了。
使用 f-string 調(diào)試
Python 3.6 中就加入了 f-string(也被稱為格式化字符串),但是在調(diào)試輸出時(shí)的代碼寫法會(huì)顯得比較重復(fù):
print(f'foo={foo} bar={bar}')
在 3.8 中,可以改用如下更簡(jiǎn)潔的寫法:
print(f'{foo=} {bar=}')
兩種寫法的輸出是一樣的。
此外,還支持使用修飾符來(lái)改變輸出的類型,比如 !s 代表使用 str() 而非 repr() 的輸出:
>>> import datetime>>> now = datetime.datetime.now()>>> print(f'{now=} {now=!s}')now=datetime.datetime(2019, 7, 16, 16, 58, 0, 680222) now=2019-07-1616:58:00.680222
僅位置參數(shù)(position-only)
新引入了一個(gè)函數(shù)參數(shù)語(yǔ)法 /,表示函數(shù)的某些參數(shù)必須按位置指定,不能用作關(guān)鍵字參數(shù)。
下面這個(gè)例子中,參數(shù) a 和 b 只能是位置參數(shù),而 c 或 d 可以是位置參數(shù),也可以是關(guān)鍵字參數(shù), e 或 f 則要求是關(guān)鍵字參數(shù):
def f(a, b, /, c, d, *, e, f):print(a, b, c, d, e, f)
可以這樣調(diào)用該函數(shù):
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 不可以是關(guān)鍵字參數(shù)f(10, 20, 30, 40, 50, f=60) # e 必須是關(guān)鍵字參數(shù)
該語(yǔ)法的一個(gè)用處,是支持純 Python 函數(shù)完整地模擬用 C 編寫的函數(shù)的行為。例如,內(nèi)置的 pow 函數(shù)是不接受關(guān)鍵字參數(shù)的:
def pow(x, y, z=None, /):"Emulate the built in pow() function"r = x ** yreturn r if z isNoneelse r%z
另外一個(gè)用處,是在參數(shù)名作用不大的情況下避免使用關(guān)鍵字參數(shù)。例如,內(nèi)置的 len() 函數(shù)的標(biāo)記是 len(obj,/),這樣可以避免下面尷尬的調(diào)用方式:
len(obj='hello') # obj 關(guān)鍵字降低了可讀性
還有一個(gè)好處,就是支持以后在不破壞客戶端代碼的前提下修改參數(shù)的名稱。例如,在 statistics 模塊中,未來(lái)可能會(huì)調(diào)整的參數(shù)名 dist,如果像下面這樣創(chuàng)建函數(shù)的話就可以實(shí)現(xiàn):
def quantiles(dist, /, *, n=4, method='exclusive')...
由于 / 左側(cè)的參數(shù)并沒(méi)有暴露為關(guān)鍵字,意味著我們后續(xù)可以在 kwargds 中繼續(xù)使用該關(guān)鍵字:
>>>>>> def f(a, b, /, **kwargs):... print(a, b, kwargs)...>>> f(10, 20, a=1, b=2, c=3) # a 和 b 有兩種用法1020 {'a': 1, 'b': 2, 'c': 3}
這樣極大地簡(jiǎn)化了那些需要接受任意關(guān)鍵字參數(shù)的函數(shù)的實(shí)現(xiàn)。下面是 collections 模塊的部分實(shí)現(xiàn),體現(xiàn)了僅位置參數(shù)的優(yōu)勢(shì)。
classCounter(dict):def __init__(self, iterable=None, /, **kwds):# Note "iterable" is a possible keyword argument
參考鏈接:
https://lwn.net/Articles/793818/
https://docs.python.org/3.8/whatsnew/3.8.html
