首先介紹的是enumerate函數(shù)。
在我們?nèi)粘>幊痰倪^程當(dāng)中,經(jīng)常會遇到一個問題。
在C語言以及一些古老的語言當(dāng)中是沒有迭代器這個概念的,所以我們要遍歷數(shù)組或者是容器的時候,往往只能通過下標(biāo)。有了迭代器之后,我們遍歷的過程方便了很多,我們可以直接用一個變量去迭代一個容器當(dāng)中的值。最簡單的例子就是數(shù)組的遍歷,比如我們要遍歷items這個數(shù)組。我們可以直接:
foriteminitems:
通過迭代器的方式我們可以很輕松地遍歷數(shù)組,而不再需要下標(biāo),也不需要計算數(shù)組的長度了。但是如果我們在循環(huán)體當(dāng)中需要知道元素的下標(biāo)該怎么辦?
難道我們真的只能在下標(biāo)和迭代器當(dāng)中選擇一個嗎,比如在循環(huán)體的外面添加一個變量來記錄下標(biāo)?
idx=0
foriteminitems:
operation()
idx+=1
這樣可以解決問題,但是很麻煩,一點也不簡潔,用專業(yè)的話來說一點也不pythonic(符合Python標(biāo)準(zhǔn)的代碼)。為了追求pythonic,于是有了enumerate函數(shù),來解決了我們又想直接迭代又需要知道元素下標(biāo)的情形。
它的用法也很簡單,我們把需要迭代的對象或者迭代器傳入enumerate函數(shù)當(dāng)中,它會為我們創(chuàng)建一個新的迭代器,同時返回下標(biāo)以及迭代的內(nèi)容。我們來看一個例子:
fori,iteminenumerate(items):
除此之外,enumerate還支持傳入?yún)?shù)。比如在某些場景當(dāng)中,我們希望下標(biāo)從1開始,而不再是0開始,我們可以額外多傳入一個參數(shù)實現(xiàn)這點:
fori,iteminenumerate(items,1):
循環(huán)是我們編程的時候必不可少的操作,也正因此,enumerate函數(shù)使用非常廣泛。但是有一點需要注意,如果我們迭代的是一個多元組數(shù)組,我們需要注意要將index和value區(qū)分開。舉個例子:
data=[(1,3),(2,1),(3,3)]
在不用enumerate的時候,我們有兩種迭代方式,這兩種都可以運行。
forx,yindata:
for(x,y)indata:
但是如果我們使用enumerate的話,由于引入了一個index,我們必須要做區(qū)分,否則會報錯,所以我們只有一種迭代方式:
fori,(x,y)inenumerate(data):
zip接下來要介紹的另一個函數(shù)同樣是方便我們迭代的,不過它針對的是另一個場景——多對象迭代。
它的應(yīng)用場景非常簡單,就是我們想要同時迭代多份數(shù)據(jù),比如用戶的名字和用戶的職業(yè)數(shù)據(jù)是分開的,我們希望同時遍歷一個用戶的職業(yè)和名字。如果不使用zip,我們可能只能放棄迭代器回到傳統(tǒng)的下標(biāo)遍歷的模式了。這樣當(dāng)然是可以的,不過有兩個小問題,第一個小問題當(dāng)然是代碼的可讀性變差了,不夠pythonic,第二個問題是我們需要維護兩個容器長度不一樣的情況,會增加額外的代碼。而使用zip,可以同時解決以上兩個問題。
我們來看一個例子:
names=['xiaoming','xiaohua','xiaohei','xiaoli']
jobs=['coach','student','student','student','professor']
forname,jobinzip(names,jobs):
print(name,job)
最后輸出的結(jié)果是人名和職業(yè)的tuple:
xiaomingcoach
xiaohuastudent
xiaoheistudent
xiaolistudent
上面舉的例子當(dāng)中,names和jobs的長度其實是不一致的,在使用了zip的情況下,會自動替我們按照其中較短的那個進(jìn)行截斷。如果我們不希望截斷,我們也可以使用itertools下的zip_longest來代替zip:
fromitertoolsimportzip_longest
forname,jobinzip_longest(names,jobs):
這樣的話長度不夠的元素會以None來填充,zip_longest提供了一個參數(shù)fillvalue,可以填充成我們指定的值。
無論是zip還是zip_longest,都可以支持多迭代器的遍歷。比如:
names=['xiaoming','xiaohua','xiaohei','xiaoli']
jobs=['coach','student','student','student','professor']
hobbies=['footbal','tennis','badminton','basketbal']
forname,job,hobbyinzip(names,jobs,hobbies):
print(name,job,hobby)
zip除了方便我們迭代遍歷之外,另一個很大的用處是可以很方便地生成dict。比如剛才的例子當(dāng)中,我們想生成一個名稱和職業(yè)的dict,一般的辦法當(dāng)然是先定義一個dict,然后遍歷所有的key和value,來生成dict。然而使用zip,我們可以將這個操作簡化到一行代碼:
jobDict=dict(zip(names,jobs))
需要注意的是,我們調(diào)用zip返回的結(jié)果其實是一個迭代器,我們在轉(zhuǎn)化成dict的時候自動遍歷了迭代器當(dāng)中的內(nèi)容。比如我們?nèi)绻苯哟蛴〕鰖ip調(diào)用結(jié)果的話,就會發(fā)現(xiàn)屏幕上輸出的是一個迭代器的地址:
print(zip(names,jobs))
>>>
我們想要獲得它的內(nèi)容,需要將它手動轉(zhuǎn)成list:
print(list(zip(names,jobs)))
>>>[('xiaoming','coach'),('xiaohua','student'),('xiaohei','student'),('xiaoli','student')]
無論是enumerate還是zip其實底層都是基于迭代器實現(xiàn)的,從原理上來說并沒有什么太深奧的內(nèi)容,而且我們不使用它們也不影響我們寫代碼。但是Python之所以是Python,之所以很多人稱道它簡潔的語言和邏輯,離不開我們廣泛地使用這些簡化代碼邏輯的工具和方法。因此我們加以了解是非常有必要的,希望大家都能寫出pythonic的代碼,不僅寫代碼能力強,而且代碼本身也漂亮。
以上內(nèi)容為大家介紹了Python之詳解enumerate和zip,希望對大家有所幫助,如果想要了解更多Python相關(guān)知識,請關(guān)注IT培訓(xùn)機構(gòu):千鋒教育。