Python專題之詳解enumerate和zip

enumerate

第一個(gè)是枚舉函數(shù)。

在我們的日常編程過(guò)程中,我們經(jīng)常遇到一個(gè)問(wèn)題。

在C語(yǔ)言和一些古老的語(yǔ)言中沒(méi)有迭代器的概念,所以當(dāng)我們想要遍歷數(shù)組或容器時(shí),我們只能使用下標(biāo)。使用迭代器,我們的遍歷過(guò)程更加方便。我們可以直接使用變量來(lái)迭代容器中的值。最簡(jiǎn)單的例子是數(shù)組遍歷。例如,我們需要遍歷items數(shù)組。我們可以直接:

for item in items:

通過(guò)迭代器的方法,可以方便地遍歷數(shù)組而不需要下標(biāo)和計(jì)算數(shù)組的長(zhǎng)度。但是如果我們需要知道循環(huán)體中元素的下標(biāo)呢?

我們真的需要在下標(biāo)和迭代器之間進(jìn)行選擇嗎,比如在循環(huán)體之外添加一個(gè)變量來(lái)記錄下標(biāo)?

idx = 0
 
for item in items:   
     operation()   
     idx += 1

這可以解決問(wèn)題,但很麻煩,一點(diǎn)也不簡(jiǎn)潔,專業(yè)術(shù)語(yǔ)也不是pythonic(Python標(biāo)準(zhǔn)代碼)。為了追求pythonic,我們使用了枚舉函數(shù)來(lái)解決直接迭代需要知道元素下標(biāo)的情況。

它的用法也很簡(jiǎn)單。我們將需要迭代的對(duì)象或迭代器傳遞到枚舉函數(shù)中。它將為我們創(chuàng)建一個(gè)新的迭代器,并返回下標(biāo)和迭代的內(nèi)容。舉個(gè)例子:

for i, item in enumerate(items):

此外,枚舉還支持傳入?yún)?shù)。例如,在某些情況下,我們希望下標(biāo)從1開(kāi)始,而不是從0開(kāi)始。我們可以傳遞一個(gè)附加參數(shù)來(lái)實(shí)現(xiàn)這一點(diǎn):

for i, item in enumerate(items, 1):

循環(huán)是我們編程中的一個(gè)基本操作。因此,枚舉函數(shù)得到了廣泛的應(yīng)用。但是,應(yīng)該注意的是,如果我們?cè)谝粋€(gè)多組數(shù)組上迭代,我們需要區(qū)分索引和值。例如:

data = [(1, 3), (2, 1), (3, 3)]

在不用enumerate的時(shí)候,我們有兩種迭代方式,這兩種都可以運(yùn)行。

for x, y in data:
 
for (x, y) in data:

但是,如果我們使用枚舉,因?yàn)橐肓怂饕?,我們必須進(jìn)行區(qū)分,否則會(huì)報(bào)告錯(cuò)誤,因此我們只有一種迭代方法:

for i, (x, y) in enumerate(data):

zip

接下來(lái)要介紹的另一個(gè)函數(shù)同樣是方便我們迭代的,不過(guò)它針對(duì)的是另一個(gè)場(chǎng)景——多對(duì)象迭代。

它的應(yīng)用場(chǎng)景非常簡(jiǎn)單,就是我們想要同時(shí)迭代多份數(shù)據(jù),比如用戶的名字和用戶的職業(yè)數(shù)據(jù)是分開(kāi)的,我們希望同時(shí)遍歷一個(gè)用戶的職業(yè)和名字。如果不使用zip,我們可能只能放棄迭代器回到傳統(tǒng)的下標(biāo)遍歷的模式了。這樣當(dāng)然是可以的,不過(guò)有兩個(gè)小問(wèn)題,第一個(gè)小問(wèn)題當(dāng)然是代碼的可讀性變差了,不夠pythonic,第二個(gè)問(wèn)題是我們需要維護(hù)兩個(gè)容器長(zhǎng)度不一樣的情況,會(huì)增加額外的代碼。而使用zip,可以同時(shí)解決以上兩個(gè)問(wèn)題。

我們來(lái)看一個(gè)例子:
image.png

最后輸出的結(jié)果是人名和職業(yè)的tuple:
xiaoming coach
xiaohua student
xiaohei student
xiaoli student

在上面的示例中,名稱和作業(yè)的長(zhǎng)度實(shí)際上不一致。使用zip時(shí),它會(huì)根據(jù)較短的zip自動(dòng)為我們截?cái)?。如果我們不想截?cái)嗨?,也可以在itertools下使用zip[最長(zhǎng)]而不是zip:

from itertools import zip_longest
for name, job in zip_longest(names, jobs):

這樣,長(zhǎng)度不足的元素將填充為“無(wú)”。Zip﹣length提供了一個(gè)參數(shù)fillvalue,可以用我們指定的值填充它。

無(wú)論是Zip還是Zip﹣long EST,它都可以支持多個(gè)迭代器的遍歷。例如:


image.png

Zip不僅便于我們迭代,而且便于我們生成dict。例如,在剛才的例子中,如果我們想生成一個(gè)名稱和職業(yè)的dict,一般的方法是先定義一個(gè)dict,然后遍歷所有鍵和值來(lái)生成一個(gè)dict。但是,使用Zip,我們可以將這個(gè)操作簡(jiǎn)化為一行代碼:

jobDict = dict(zip(names, jobs))

需要注意的是,我們調(diào)用zip的結(jié)果實(shí)際上是一個(gè)迭代器。當(dāng)我們將其轉(zhuǎn)換為dict時(shí),我們會(huì)自動(dòng)遍歷迭代器的內(nèi)容。例如,如果直接打印zip調(diào)用的結(jié)果,我們會(huì)發(fā)現(xiàn)屏幕上的輸出是迭代器的地址:

print(zip(names, jobs))
>>> <zip object at 0x10ec93b40>

我們想要獲得它的內(nèi)容,需要將它手動(dòng)轉(zhuǎn)成list:

print(list(zip(names, jobs)))
>>> [('xiaoming', 'coach'), ('xiaohua', 'student'), ('xiaohei', 'student'), ('xiaoli', 'student')]

實(shí)際上,枚舉和zip的底層都是基于迭代器實(shí)現(xiàn)的。原則上,沒(méi)有深刻的內(nèi)容,我們也不使用它們來(lái)編寫(xiě)代碼。但Python之所以是Python,以及為什么許多人稱之為簡(jiǎn)明語(yǔ)言和邏輯,是因?yàn)槲覀儚V泛使用這些工具和方法來(lái)簡(jiǎn)化代碼邏輯。所以我們很有必要去理解它。我希望每個(gè)人都能寫(xiě)出Python IC的代碼,Python IC不僅在編寫(xiě)代碼方面很強(qiáng)大,而且本身也很漂亮。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容