海象運(yùn)算符
這個(gè)新運(yùn)算符 :=
能讓我們?yōu)楸磉_(dá)式中的一個(gè)變量賦值,這個(gè)符號(hào)看起來頗有些類似于海象的眼睛和犬齒纸型。
我們先來看看下面一段代碼:
countries = [“India”, “USA”, “France”, “Germany”]
if len(countries) < 5:
print ("Length of countries is " + len(countries))
在上面的代碼段中,我們兩次調(diào)用了函數(shù) len()梅忌。我們可以避免重復(fù)計(jì)算以提升可讀性嗎狰腌?當(dāng)然可以,我們可對(duì)這段代碼進(jìn)行如下改進(jìn):
country_size = len(countries)
if country_size < 5:
print ("Length of countries is " + country_size)
還有進(jìn)一步改進(jìn)的空間嗎铸鹰?我們可以不用單獨(dú)一行來給「country_size」賦值嗎癌别?
if country_size := len(countries) < 5 :
print ("Length of countries is " + country_size)
這就是 Python 3.8 引入的海象運(yùn)算符的用武之地。我們可以在 if 語句之中直接執(zhí)行聲明和賦值操作蹋笼。我們下面進(jìn)一步探索該運(yùn)算符的能力展姐。
代碼行數(shù)與復(fù)雜度的平衡
先看看以下示例(多次調(diào)用一個(gè)高成本的函數(shù))
powers = [get_count(), get_count()**2, get_count()**3]
def get_count():
"Fetches count of records from a database"
上面的示例是通過多次調(diào)用一個(gè)高成本的函數(shù) get_count() 來填充一個(gè)列表。
有了海象運(yùn)算符的幫助剖毯,我們可以避免多次調(diào)用函數(shù) get_count()圾笨,其具體的功能是將結(jié)果存儲(chǔ)到一個(gè)變量中,然后我們可在后續(xù)的計(jì)算中復(fù)用同一個(gè)變量逊谋。
下面演示了海象運(yùn)算符的用法:
powers =[result:= get_count(), result**2, result**3]
def get_count():
"Fetches count of records from a database"
從上面的例子可以看到擂达,海象運(yùn)算符可以減少代碼行數(shù),讓代碼更可讀胶滋,因此能簡化代碼審查人員的工作板鬓。此外,這也能實(shí)現(xiàn)代碼行數(shù)和代碼復(fù)雜度的平衡究恤。
解決理解低效的問題
employees = []
for id in employee_ids:
employee = fetch_employee(id)
if employee:
employees.append(employee)
基于一個(gè)條件填充列表
上面的示例需要多次執(zhí)行循環(huán)俭令。一開始,我們創(chuàng)建一個(gè)空列表部宿,然后在 id 列表上迭代并通過檢查結(jié)果是否有效來填充我們創(chuàng)建的列表抄腔。
我們可以簡化上面的代碼,將其濃縮為一行:
employees = [result for id in employee_ids if (result:= fetch_employee(id))]
# 使用海象運(yùn)算符避免低效理解
文件分塊處理
在處理大文件時(shí)理张,我們會(huì)將文件分塊讀取赫蛇。每當(dāng)讀取一個(gè)分塊時(shí),都會(huì)檢查它的值雾叭,并且該值也是 while 循環(huán)的終止條件悟耘。
chunk = file.read(256)
while chunk:
process(chunk)
chunk = file.read(256)
我們可以在 while 循環(huán)表達(dá)式中讀取數(shù)據(jù)以及為要讀取的數(shù)據(jù)賦值。由此我們就能避免在 while 循環(huán)之外顯式地聲明變量织狐。如下示例:
while chunk := file.read(256) :
process(chunk)
正則表達(dá)式匹配
正則表達(dá)式匹配是一個(gè)兩步式過程暂幼。第一步是檢查是否有匹配掘殴,第二步是提取匹配的部分。
obj = re.match(info).group(1) if re.match(info) else None
#正則表達(dá)式匹配
從上面的代碼可以觀察到粟誓,我們?cè)谝淮纹ヅ渲兄貜?fù)計(jì)算了 re.match(info)奏寨。這會(huì)減慢該程序的執(zhí)行速度,而且數(shù)據(jù)量越大減慢得越明顯鹰服。上面的代碼可以重寫為如下形式病瞳,從而避免重復(fù)計(jì)算:
obj = match.group(1) if match:= re.match(info) else None
#使用 := 的正則表達(dá)式匹配
不能使用海象運(yùn)算符的地方
為變量賦值
a = 5 # 有效
a := 5 # 無效
empty_list = [] # 有效
empty_list := [] # 無效
如上所示,我們不能使用 := 替代 =悲酷。海象運(yùn)算符只能是一個(gè)表達(dá)式的一部分套菜。
加法/減法賦值
a += 5 # 有效
a :+=5 # 無效
在 lambda 函數(shù)中為表達(dá)式賦值
(lambda: a:= 5) # 無效
lambda: (a := 5) # 有效但無用
(var := lambda: 5) # 有效
PEP-572 及其爭議
海象預(yù)算符的爭議點(diǎn)有很多,下面是其中幾個(gè):
句法變化問題:開發(fā)者們?yōu)?:=
提議了多種替代方案设易,比如「表達(dá)式 -> NAME
」逗柴、「NAME -> 表達(dá)式
」、「{表達(dá)式} NAME
」等等顿肺。少數(shù)人建議使用現(xiàn)有的關(guān)鍵字戏溺,其他人則使用了新的運(yùn)算符。
后向兼容問題:這個(gè)特性無法向后兼容屠尊,也無法運(yùn)行在之前的 Python 版本上旷祸。
運(yùn)算符名稱問題:人們建議不要使用「海象運(yùn)算符」這樣的代號(hào),而是使用「賦值運(yùn)算符」讼昆、「命名表達(dá)式運(yùn)算符」托享、「成為運(yùn)算符」等術(shù)語,以免人們不明白浸赫。