淺析PEP572: 海象運(yùn)算符
現(xiàn)在已經(jīng)是Python 3.8的最后一個alpha版本,接著就是本月底要發(fā)布的的3.8.0 beta 1了。按規(guī)定,3.8已經(jīng)不會再添加(修改)功能了,之前非常有爭議的PEP 572的實(shí)現(xiàn)已經(jīng)算是很固定了,我們這篇文章就來先嘗個鮮??纯催@個新的賦值表達(dá)式語法怎么用,何時用。
海象運(yùn)算符
PEP572的標(biāo)題是「Assignment Expressions」,也就是「賦值表達(dá)式」,也叫做「命名表達(dá)式」,不過它現(xiàn)在被廣泛的別名是「海象運(yùn)算符」(The Walrus Operator)。因?yàn)?=很像海象「眼睛小,長著兩枚長長的牙」這個特點(diǎn)^_^。
語法和語義
我們不詳細(xì)介紹PEP的內(nèi)容,直接說應(yīng)用場景。我覺得它主要可以用在2個地方
賦值給中間變量
這個小標(biāo)題想了很久,沒找到更合適能表達(dá)的。不過相信通過2個例子相信大家就能理解了。
首先是一個正則匹配的例子:
pattern = re.compile('s') data = 'ss' if pattern.match(data): print(pattern.match(data).group(0))
如果能匹配到條件,match 對象才會有g(shù)roup 方法。但是這樣寫雖然節(jié)省到一行代碼卻讓執(zhí)行變慢了,因?yàn)橹貜?fù)地執(zhí)行了2次re.match(data)。正確的寫法是:
match = pattern.match(data) if match: print(match.group(0))
代碼也就只能寫成這樣了,但如果使用賦值表達(dá)式:
if (match := pattern.match(data)) is not None: print(match.group(0))
本來if這種控制結(jié)構(gòu)語句只是求值表達(dá)式,看結(jié)果是不是符合條件。而在這里,它做了3件事:
- 對表達(dá)式pattern.match(data)求值
- 把值的結(jié)果賦值給match
- 把match 作為if的條件,判斷它的值是不是None
我對它的理解是: 求值過程中也賦值了新的中間變量,這個(些)中間變量(如這里的match)可以在代碼塊中被繼續(xù)使用。
再看一個文件讀取的例子:
while 1: line = fp.readline() if not line: break print(line)
現(xiàn)在可以直接寫成:
while (line := fp.readline()): print(line)
這可以說是一種代碼風(fēng)格的改進(jìn)了。
簡化列表解析
列表解析性能好,而且非常 pythonic,但是它應(yīng)用場景有限,我們看個例子:
results = [] for x in data: result = f(x) if result: results.append(result)
這是一個日常開發(fā)里面比較常見的結(jié)構(gòu)?,F(xiàn)在是不能用列表解析的,不信的話下面的方案:
results = [ f(x) for x in data if f(x) ]
這個是錯誤的,每次循環(huán)執(zhí)行了2 次f函數(shù)?,F(xiàn)在用賦值表達(dá)式可以寫成:
results = [ y for x in data if (y := f(x)) ]
可以用列表解析了!
再看一個PEP提的例子:
stuff = [[y := f(x), x/y] for x in range(5)]
其實(shí)又回到了賦值給中間變量這個點(diǎn),每一項(xiàng)包含了y,以及要用y才能獲得結(jié)果的x/y。
上面說的就是海象運(yùn)算符能實(shí)現(xiàn)的目的了~
Golang里面的:=
:=并不是Python首創(chuàng)的,Golang里面有一個短變量聲明(Short variable declarations)語法:
// ShortVarDecl = IdentifierList ":=" ExpressionList . i, j := 0, 10 f := func() int { return 7 } func f(n int) (res int, err error) { if _, err := f(n-1); err != nil { return } return }
:=的作用是替代 var 定義,聲明時不需要指定類型。同時由于語言設(shè)計,和Python的賦值表達(dá)式一樣,如上面的例子,f(n-1)的第二個返回值err可以被后面的err != nil使用,用來判斷條件是否成立,我非常喜歡!
我對PEP 572的看法
在之前我曾經(jīng)在知乎回答過「如何看待 PEP 572 ?」這個問題,當(dāng)時我這么說:
這個PEP 有明確的 Recommended use-cases, 在正確的地方使用,而不是濫用,當(dāng)然不喜歡的可以不用,用舊的形式。我語言提供了更多特性和選擇的機(jī)會,但控制權(quán)是開發(fā)者手里的,就像元類、描述符、dataclass 甚至裝飾器等等都是有適用場景的。
有人覺得它不符合Python之禪,其實(shí)我個人感覺挺好的呀?,F(xiàn)在PEP 572的實(shí)現(xiàn)已經(jīng)合并到Python3.8,試用下來非常贊。
Dustin Ingram在PyCON2019上做了一個《PEP 572: The Walrus Operator》的分享,最后他也說自己不喜歡這個語法,但是他接著說:
You might say well i don't like it, that's totally fine. you don't have to like it if you don't like it then don't write it
我覺得說的非常好,沒人強(qiáng)制你必須使用它~
好了,本文就給大家介紹到這里,希望對大家有所幫助!
相關(guān)文章
Python實(shí)現(xiàn)的棧、隊(duì)列、文件目錄遍歷操作示例
這篇文章主要介紹了Python實(shí)現(xiàn)的棧、隊(duì)列、文件目錄遍歷操作,結(jié)合實(shí)例形式分析了Python數(shù)據(jù)結(jié)構(gòu)中棧與隊(duì)列的定義、使用,以及文件目錄的遍歷相關(guān)操作技巧,需要的朋友可以參考下2019-05-05Python利用PyMuPDF實(shí)現(xiàn)PDF文件處理
PyMuPDF是MuPDF的Python綁定-“輕量級PDF和XPS查看器”。本文將利用PyMuPDF實(shí)現(xiàn)PDF的一些基本操作,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-05-05pygame實(shí)現(xiàn)俄羅斯方塊游戲(對戰(zhàn)篇1)
這篇文章主要為大家詳細(xì)介紹了pygame實(shí)現(xiàn)俄羅斯方塊游戲的對戰(zhàn)篇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-10-10python實(shí)現(xiàn)簡單的TCP代理服務(wù)器
這篇文章主要介紹了python實(shí)現(xiàn)簡單的TCP代理服務(wù)器,包含了完整的實(shí)現(xiàn)過程及對應(yīng)的源碼與說明文檔下載,非常具有參考借鑒價值,需要的朋友可以參考下2014-10-10Python?turtle.shape()用法及實(shí)戰(zhàn)案例
turtle是Python自帶的一個小型的繪圖庫,它可以幫助我們快速地繪制簡單的圖形,這篇文章主要給大家介紹了關(guān)于Python?turtle.shape()用法及實(shí)戰(zhàn)案例的相關(guān)資料,需要的朋友可以參考下2024-03-03python?中的?BeautifulSoup?網(wǎng)頁使用方法解析
這篇文章主要介紹了python?中的?BeautifulSoup?網(wǎng)頁使用方法解析,文章基于python的相關(guān)資料展開詳細(xì)內(nèi)容介紹,具有一定的參考價值需要的小伙伴可以參考一下2022-04-043種Python 實(shí)現(xiàn)酷炫進(jìn)度條的實(shí)用方法
這篇文章主要介紹了3種Python 實(shí)現(xiàn)酷炫進(jìn)度條的實(shí)用方法,文章圍繞Python的相關(guān)資料展開對實(shí)現(xiàn)進(jìn)度條的介紹,需要的小伙伴可以參考一下2022-04-04