當掃瞄記憶體中放不下的資料集時,我們需要找到一種惰性獲取資料項的方式,每次「取出」1個。
這就是迭代器相對於普通可迭代物件的優勢:節省記憶體
l =[,
'orange'
,'pear'
]#列表就是乙個可迭代物件
在python中,很多內建的資料型別都是可迭代物件,如列表,字串,元組,字典,集合等
如果要自己構建乙個可迭代的資料型別,只需要實現乙個__getitem__()方法。
接下來實現乙個sentence類,傳入乙個以空格分隔的英文句子,迭代句子中的單詞。
class
sentence
:def
__init__
(self, text)
: self.words = text.split(
)def
__getitem__
(self, index)
:return self.words[index]
現在測試一下這個sentence類
>>
> sen = sentence(
'hello my world my name is alfred'
)>>
> sen
<__main__.sentence object at 0x02cf5f30
>
>>
> sen.words
['hello'
,'my'
,'world'
,'my'
,'name'
,'is'
,'alfred'
]>>
> sen[3]
'my'
>>
>
for i in sen:
print
(i)hello
myworld
myname
isalfred
剛才我利用__getitem__()構建了乙個可迭代物件sen,
那麼如果我要構建乙個迭代器,應該使用的魔法方法是__next__()和__iter__()
接下來利用__next__()和__iter__()構建乙個sentence2類。
class
sentence2
:def
__init__
(self, text)
: self.words = text.split(
) self.index =
0def
__next__
(self)
:try
: word = self.words[self.index]
except indexerror:
raise stopiteration(
) self.index +=
1return word
def__iter__
(self)
:return self
同樣地,現在來測試一下這個sentence2類
>>
> sen2 = sentence2(
'hello my world my name is alfred'
)>>
> sen2.words
['hello'
,'my'
,'world'
,'my'
,'name'
,'is'
,'alfred'
]>>
> sen2[5]
traceback (most recent call last)
: file ""
, line 1,in
sen2[5]
typeerror:
'sentence2'
object does not support indexing
>>
>
for i in sen2:
print
(i)hello
myworld
myname
isalfred
>>
>
sen2的索引操作引發了typeerror異常,然而從for迴圈中可以看出,sen2依然是可迭代的。其實這裡還有乙個很神奇的現象,如果對sen2進行第二次for迴圈,會發現什麼都得不到,sen2裡面是空的。
>>
>
for i in sen2:
print
(i)>>
>
實際上,當我們迭代乙個物件x的時候,直譯器會自動呼叫內建的iter(x)函式。它的作用有3個:
(1)檢查物件是否實現了__iter__()方法,如果實現了就呼叫它,返回乙個迭代器。
(2)如果沒有實現__iter__(),就檢查是否實現了__getitem__()方法,python會自動建立乙個迭代器,並從索引0開始獲取元素。
(3)如果2個方法都沒有實現,那麼就只能丟擲typeerror異常了「x object is not iterable」
為什麼在上述的sen2例項中,進行第二次迭代的時候,sen2會沒有元素可以迭代呢?
這是由於__iter__()方法使其自身成為了迭代器,當迭代的時候,next()方法會不斷地返回序列中的下乙個元素,最終導致耗盡了其自身的元素,然後丟擲stopiteration異常。
為了讓迭代器可以一直迭代,iter()方法應該是返回乙個迭代器,而不是讓其自身稱為乙個迭代器
所以,迭代器更準確的實現方式應該是只實現乙個__iter__()方法,而__next__()方法應該封裝在另乙個類中,該類表示了迭代器的內部狀態:
譬如如下sentence3類:
class
sentence3
:def
__init__
(self, text)
: self.words = text.split(
)def
__iter__
(self)
:return sentenceiter(self.words)
class
sentenceiter
:def
__init__
(self, words)
: self.words = words
self.index =
0def
__next__
(self)
:try
: word = self.words[self.index]
except indexerror:
raise stopiteration(
) self.index +=
1return word
def__iter__
(self)
:return self
現在sen3可以一直迭代了
>>
> sen3 = sentence3(
'hello my world my name is alfred'
)>>
> sen3.words
['hello'
,'my'
,'world'
,'my'
,'name'
,'is'
,'alfred'
]>>
>
for i in sen3:
print
(i)
hello
myworld
myname
isalfred
>>
>
for i in sen3:
print
(i)
hello
myworld
myname
isalfred
>>
>
總的來說: python迭代 可迭代物件與迭代器物件
問題舉例 某軟體要求,從網路抓取各個城市的氣溫資訊,並依次顯示 北京 15 22 上海 18 23 如果一次抓取所有城市氣溫資訊再顯示,顯示第乙個城市的氣溫時會由很長的延時,並且浪費儲存空間,我們期望以 用時訪問 的策略,並且把所有城市的氣溫資訊封裝 到乙個物件裡,可用for語句進行迭代。來個栗子 ...
python 迭代器與可迭代物件
主要有兩個方法next 與iter next不斷返回下乙個元素,知道元素全部返回後出現異常,可以節省記憶體空間。iter是迭代,可以把乙個列表直接轉換成迭代器,然後使用next 方法。data list 1,2,3,4,5 data list iter data list print next da...
Python 迭代器與可迭代物件
迭代器可以讓我們訪問集合的時候變得非常方便。之前我們通過for.in.的方式訪問乙個集合的時候,就是使用迭代器完成的。如果沒有迭代器,那麼我們只能通過while迴圈,每次迴圈的時候通過下標訪問了。可以直接使用for迴圈遍歷的物件,成為可迭代的物件,常見的可迭代的物件有 list tuple dict...