Python之可迭代物件 迭代器

2021-10-21 06:47:09 字數 4054 閱讀 9002

python的特色之一是基於協議實現功能。比如改變乙個加號(+)的行為,在c++中需要操作符過載,在python中則是重寫__add__方法。為了描述可迭代物件和迭代器,python提供了兩個魔法方法,分別是__iter__和__next__。又為了支援for...in...行為,牽扯進了__getitem__。

眾所周知使用for迴圈可以遍歷的物件有:字典,列表,元祖,字串,集合。我們稱之為遍歷,也叫作迭代。可以直接作用於 for 迴圈的物件統稱為 可迭代物件。

可迭代物件在 python 中是一種更加普遍和通用的概念,它出現在目前 python 方方面面的設計和實現中。我們可以在各種迭代環境中(常用的 for 迴圈、列表推導、zip()、map() 等)使用可迭代物件來進行迭代,比如對於 for 迴圈而言,它並不拘泥於只可使用序列型別來進行迭代,對於所有可迭代物件而言,它都支援在 for 迴圈中進行迭代。

從表面來看,可迭代物件是一種可以逐一返回其成員元素的物件,它可以在每次的迭代過程中產生乙個成員元素;從基礎的定義來看,可迭代物件是指支援 iter() 呼叫的物件;從涵蓋範圍來看,可迭代物件包括定義了 __iter__ 方法或 __getitem__ 方法的自定義物件,以及包括 list、tuple、str 等在內的所有序列型別和包括 dict、set、file objects 等在內的某些非序列型別。

迭代器和可迭代物件的關係十分密切,但迭代器相較於可迭代物件而言,它和整個迭代過程的聯絡更加的深入。為了更好的理解可迭代物件和迭代器在迭代中的作用,我們先從迭代過程入手,以最基本的 for 迴圈迭代過程為例子,先看一段簡單的**:

d = 

for i in d:

print(i)

在上面的for迴圈過程中,可迭代物件d會先通過iter()生成乙個迭代器iter(d), 該迭代器具有乙個__next__方法。在每次迭代過程中,這個__next__方法會被呼叫,從而返回d中的下乙個鍵,直至字典的鍵全部返回後,__next__會引發stopiteration異常,而for迴圈則會通過捕捉該異常來終止迭代。

顯而易見的是這整個過程都是由迭代工具 for 迴圈內自動支援的。在迭代環境中使用可迭代物件時,我們通常不需要自己來完成呼叫 iter() 並對生成的迭代器使用臨時變數進行儲存等過程,迭代工具會幫我們自動完成這些處理過程。

在 python 其他迭代工具(比如列表推導、in成員關係檢測、map()等)中的迭代過程和上面的描述是基本一致的。

現在有了上面對迭代過程的大致了解,我們便可以給出迭代器的基本概念。迭代器物件可以用於表示一串資料流,其具有__next__方法,支援next()呼叫,不斷地呼叫其__next__方法可以逐個返回資料流中的每一項,當到達資料流的末尾時,再繼續呼叫__next__方法則會引發stopiteration異常。同時,迭代器物件也具有__iter__方法(所以迭代器物件一定是可迭代物件),該方法通常會返回迭代器本身,因此在通常情況下迭代器僅支援單次的迭代(在一次迭代後迭代器就會被耗盡),而不會像list等其他可迭代物件那樣,可以支援多次的迭代(因為每次使用iter()中傳入list物件時都會生成乙個新的迭代器)。

注意:python的iterator是乙個惰性序列,意思是表示式和變數繫結後不會立即進行求值,而是當你用到其中某些元素的時候才去求某元素對的值。 惰性是指,你不主動去遍歷它,就不會計算其中元素的值。

乙個使用者自定義的類可以通過定義 __iter__ 或 __getitem__ 來支援迭代,對於 __iter__ 支援迭代的具體過程我們已經進行了了解,那麼在迭代中 __getitem__ 和 __iter__ 的關係是怎麼樣的呢?

在迭代過程中可迭代物件 object 被傳入 iter() 函式中,iter() 會優先呼叫 object 的 __iter__ 方法,若沒有找到 __iter__ 方法時,iter() 才會嘗試使用 __getitem__ 來支援可迭代。那 __getitem__ 具體是如何支援迭代的呢?首先我們需要了解 __getitem__ 的基本作用。

這裡涉及到運算子過載的相關的知識,object.__getitem__(self, key) 可以用於實現類似 self[key] 這樣的索引操作。

__getitem__ 方法也可以用於支援迭代,它的基本原理便是在迭代中通過從 0 開始不斷增大的索引值來對某個序列進行索引操作同時返回對應的結果,最後通過捕獲 indexerror 來終止迭代。當然,在我們自定義物件來支援迭代的時候,應優先考慮使用最直接的 __iter__ 方法。

下面通過**來理解上面的概念:

from collections.abc import iterator

class company(object):

def __init__(self, employee_list):

self.employee = employee_list

def __iter__(self):

return companyiterator(self.employee)

def __getitem__(self, item):

return self.employee[item]

class companyiterator(iterator):

def __init__(self, employee_list):

self.iter_list = employee_list

self.index = 0

def __next__(self):

#真正返回迭代值的邏輯

try:

word = self.iter_list[self.index]

except indexerror:

raise stopiteration

self.index += 1

return word

if __name__ == "__main__":

company = company(["tom", "bob", "jane"])

my_itor = iter(company)

while true:

try:

print(next(my_itor))

except stopiteration:

break

print(company[0])

for item in company:

print (item)

在這裡,以簡要概括的角度對可迭代物件和迭代器需要支援的方法進行乙個總結:

可以通過isinstance()來判斷,這裡需要借助於collections.abc中定義的一些容器抽象基類,這些抽象基類包括了containerhashableiterablesequence等,可以用於判斷乙個具體的物件是否具有某些特定的介面。

from collections.abc import iterable, iterator

a = [1,2]

iter_rator = iter(a)

print (isinstance(a, iterable)) # true

print (isinstance(iter_rator, iterator)) # true

print (isinstance(a, iterator)) # false

PYTHON 迭代器 可迭代物件

通過重複執行的 處理相似的資料集的過程,並且本次迭代的處理資料要依賴上一次的結果繼續往下做,上一次產生的結果為下一次產生結果的初始狀態,如果中途有任何停頓,都不能算是迭代。1 非迭代例子 loop 0 while loop 3 print hello world loop 1 2 迭代例子 loop...

python迭代 可迭代物件與迭代器物件

問題舉例 某軟體要求,從網路抓取各個城市的氣溫資訊,並依次顯示 北京 15 22 上海 18 23 如果一次抓取所有城市氣溫資訊再顯示,顯示第乙個城市的氣溫時會由很長的延時,並且浪費儲存空間,我們期望以 用時訪問 的策略,並且把所有城市的氣溫資訊封裝 到乙個物件裡,可用for語句進行迭代。來個栗子 ...

迭代器 可迭代物件 迭代器物件

今天的學習內容有 迭代器 可迭代物件 迭代器物件 for迴圈內部原理 生成器和生成器表示式 面向過程程式設計 迭代就是指更新換代的過程,要重複進行,而且每次的迭代都必須基於上一次的結果。我們使用for迴圈的時候就是把元素從容器裡乙個個取出來,這種過程其實就是迭代。迭代器 迭代取值的工具。迭代器的作用...