Python之迭代器

>可迭代對象和迭代器傻傻分不清

之前自己一直沒搞明白可迭代對象和迭代器的關(guān)系纽匙,總覺得兩個沒有區(qū)別,這次再來一探究竟

先來理解個概念

可迭代對象(iterable)是可以迭代的任何東西绰更,迭代器(iterator)是執(zhí)行實際迭代的東西

>可迭代對象

讓我們從熟悉的數(shù)據(jù)類型說起吧

In [1]: iter([1,2,3])
Out[1]: <list_iterator at 0x7fd6a01650f0>

In [2]: iter((1,2,3))
Out[2]: <tuple_iterator at 0x7fd6a0b57860>

In [3]: iter("hello word")
Out[3]: <str_iterator at 0x7fd6a0b57be0>

In [5]: iter(1)
TypeError: 'int' object is not iterable

看Out輸出的內(nèi)容,TypeError: 'int' object is not iterable,這句話的意思就是int類型不是一個可迭代對象燎猛,那為何上面的list/tuple/str沒有報錯呢?難道它們就是可迭代對象溉瓶?這三種數(shù)據(jù)類型經(jīng)過iter()方法后返回iterator迭代器急鳄?為什么呢...

為了驗證我們的猜想谤民,使用isinstance()來做個了結(jié)

In [17]: from collections import Iterable

In [19]: isinstance([1,2,3], Iterable)
Out[19]: True

In [20]: isinstance((1,2,3), Iterable)
Out[20]: True

In [21]: isinstance("hello word", Iterable)
Out[21]: True

In [22]: isinstance(1, Iterable)
Out[22]: False

經(jīng)過我們的驗證,list/tuple/str 是可迭代對象疾宏,int就不是张足,那list/tuple/str和int有什么區(qū)別呢?

細心的你發(fā)現(xiàn)坎藐,可迭代對象都是可以用for循環(huán)遍歷的为牍?而int就不可以,真的是這樣嗎岩馍?for循環(huán)和可迭代對象有關(guān)系嗎碉咆?不急,我們再來驗證下...

In [23]: for i in [1,2,3]:
    ...:     print(i)
    ...:
1
2
3

In [24]: for i in (1,2,3):
    ...:     print(i)
    ...:
1
2
3

In [25]: for i in "hello":
    ...:     print(i)
    ...:
h
e
l
l
o

In [27]: for i in 1:
    ...:     print(i)
    ...:
TypeError: 'int' object is not iterable

過不奇然蛀恩,和我們猜想的一致疫铜,當我們對1使用for循環(huán)時,報出錯誤TypeError: 'int' object is not iterable双谆,其它的就沒有壳咕,難道for循環(huán)的條件也是需要一個可迭代對象?

廢話這么多顽馋,那什么是可迭代對象呢谓厘?下面可要畫重點了數(shù)據(jù)類型實現(xiàn)了iter方法的就是一個可迭代對象,那我們順著這個線索去驗證下,不能你說對就對寸谜,一起來看看吧竟稳!

In [29]: class Mylist(object):
    ...:     def __init__(self):
    ...:         self.container = []
    ...:     def add(self, item):
    ...:         self.container.append(item)
    ...:

In [30]: mylist = Mylist()

In [31]: mylist.add(1)

In [32]: mylist.add(2)

In [33]: for i in mylist:
    ...:     print(i)
    ...:
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-33-082208dcc545> in <module>
----> 1 for i in mylist:
      2     print(i)
      3
TypeError: 'Mylist' object is not iterable

有結(jié)論嗎?不急不急程帕,再來看一個

In [35]: class Mylist(object):
    ...:     def __init__(self):
    ...:         self.container = []
    ...:     def add(self, item):
    ...:         self.container.append(item)
    ...:     def __iter__(self):
    ...:         pass
    ...:
In [36]: mylist = Mylist()

In [37]: mylist.add(1)

In [38]: mylist.add(2)

In [39]: for i in mylist:
    ...:     print(i)
    ...:
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-39-082208dcc545> in <module>
----> 1 for i in mylist:
      2     print(i)
      3
TypeError: iter() returned non-iterator of type 'NoneType'

In [40]: from collections import Iterable

In [41]: isinstance(mylist, Iterable)
Out[41]: True

仔細的觀眾已經(jīng)看出了貓膩束亏,一個數(shù)據(jù)類型是否是可迭代對象關(guān)系到它是否實現(xiàn)了iter方法,至此靴庆,關(guān)于可迭代對象已經(jīng)說明白了

那迭代器呢匣摘?細心的觀眾又發(fā)現(xiàn)了,在我們用for循環(huán)遍歷mylist時岭埠,報出了錯誤TypeError: iter() returned non-iterator of type 'NoneType'盏混,到此,我們可以知道惜论,for循環(huán)遍歷的過程中许赃,調(diào)用了iter()方法報出了return non-iterator,說iter()返回的不是一個迭代器,龜龜馆类,這就把迭代器引出來了混聊,既然出來了,那就看看吧乾巧!

我們在Mylist類中句喜,實現(xiàn)了iter方法预愤,但是沒有具體的實現(xiàn),當我們使用for循環(huán)時咳胃,并沒有報出'Mylist' object is not iterable的錯誤植康,那我們就可以推斷Mylist是一個可迭代對象,但接下來卻報出了return non-iterator展懈,說明for循環(huán)遍歷時需要一個迭代器销睁,而這個迭代器是iter()方法返回的,至此存崖,我們可以得到一個結(jié)論冻记,迭代器是可迭代對象;那什么又是迭代器呢金句?

我們將目光轉(zhuǎn)移到文章的開始

In [1]: iter([1,2,3])
Out[1]: <list_iterator at 0x7fd6a01650f0>

In [2]: iter((1,2,3))
Out[2]: <tuple_iterator at 0x7fd6a0b57860>

In [3]: iter("hello word")
Out[3]: <str_iterator at 0x7fd6a0b57be0>

In [5]: iter(1)
TypeError: 'int' object is not iterable

我們對list/tuple/str數(shù)據(jù)類型使用iter方法時,返回的結(jié)果時**_iterator,這是一個迭代器贞瞒,我們對比Mylist這個類趁曼,它是一個可跌代對象军浆,iter()返回的卻不是一個迭代器,那這個迭代器就是這個iter()方法返回的挡闰?那iter()內(nèi)部需要怎么實現(xiàn)呢?

In [2]: from collections import Iterator

In [3]: isinstance([1,2,3], Iterator)
Out[3]: False

In [4]: isinstance(iter([1,2,3]), Iterator)
Out[4]: True

In [5]: isinstance("hello", Iterator)
Out[5]: False

In [6]: isinstance(iter("hello"), Iterator)
Out[6]: True

接下來再看個例子

In [22]: it = iter("hello")

In [23]: next(it)
Out[23]: 'h'

In [24]: next(it)
Out[24]: 'e'

In [25]: next(it)
Out[25]: 'l'

In [26]: next(it)
Out[26]: 'l'

In [27]: next(it)
Out[27]: 'o'

In [28]: next(it)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-28-bc1ab118995a> in <module>
----> 1 next(it)

StopIteration:

每次調(diào)用next()都返回一個值赞季,這個和for的遍歷是不是相同呢?還記得我們在Mylist類中使用for遍歷它的實例奢驯,返回TypeError: iter() returned non-iterator of type 'NoneType'申钩,說iter()返回的不是迭代器。再結(jié)合上面和for循環(huán)對字符串的遍歷撒遣,是否next()就是實現(xiàn)迭代器的關(guān)鍵呢管跺?那就來試試

In [38]: class Mylist(object):
    ...:     def __init__(self):
    ...:         self.container = []
    ...:     def add(self, item):
    ...:         self.container.append(item)
    ...:     def __iter__(self):
    ...:        myiterator =  MyIterator(self)
    ...:        return myiterator
    ...:
In [39]: class MyIterator(object):
    ...:     def __init__(self,mylist):
    ...:         self.mylist = mylist
    ...:         self.current = 0
    ...:     def __next__(self):
    ...:         if self.current < len(self.mylist.container):
    ...:             item = self.mylist.container[self.current]
    ...:             self.current += 1
    ...:             return item
    ...:         else:
    ...:             raise StopIteration
    ...:     def __iter__(self):
    ...:         return self
    ...:
In [40]: mylist = Mylist()

In [41]: mylist.add(1)

In [42]: mylist.add(2)

In [43]: mylist.add(3)

In [44]: mylist.add(4)

In [45]: mylist.add(5)

In [46]: for i in mylist:
    ...:     print(i)
    ...:
1
2
3
4
5

In [47]:

我們發(fā)現(xiàn)可以使用for循環(huán)遍歷數(shù)據(jù)了,我們來做一個斐波那契數(shù)列的迭代器

In [54]: class FibIterator(object):
   ...:     """斐波那契數(shù)列迭代器"""
   ...:     def __init__(self, n):
   ...:         """
   ...:         :param n: int, 指明生成數(shù)列的前n個數(shù)
   ...:         """
   ...:         self.n = n
   ...:         # current用來保存當前生成到數(shù)列中的第幾個數(shù)了
   ...:         self.current = 0
   ...:         # num1用來保存前前一個數(shù),初始值為數(shù)列中的第一個數(shù)0
   ...:         self.num1 = 0
   ...:         # num2用來保存前一個數(shù)廉涕,初始值為數(shù)列中的第二個數(shù)1
   ...:         self.num2 = 1
   ...:
   ...:     def __next__(self):
   ...:         """被next()函數(shù)調(diào)用來獲取下一個數(shù)"""
   ...:         if self.current < self.n:
   ...:             num = self.num1
   ...:             self.num1, self.num2 = self.num2, self.num1+self.num2
   ...:             self.current += 1
   ...:             return num
   ...:         else:
   ...:             raise StopIteration
   ...:
   ...:     def __iter__(self):
   ...:         """迭代器的__iter__返回自身即可"""
   ...:         return self
   ...:

In [55]: fb = FibIterator(10)

In [56]: next(fb)
Out[56]: 0

In [57]: next(fb)
Out[57]: 1

In [58]: next(fb)
Out[58]: 1

In [59]: for i in fb:
   ...:     print(i)
   ...:
2
3
5
8
13
21
34

至此,我們來總結(jié)下可迭代對象和迭代器

實現(xiàn)了iter()方法的就是可迭代對象火的;實現(xiàn)了Iter()和next()方法的就是迭代器

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末馏鹤,一起剝皮案震驚了整個濱河市娇哆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌碍讨,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宵统,死亡現(xiàn)場離奇詭異覆获,居然都是意外死亡,警方通過查閱死者的電腦和手機痊班,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門摹量,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凝果,你說我怎么就攤上這事睦尽∑骶唬” “怎么了骂删?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宁玫。 經(jīng)常有香客問我,道長眷射,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任涌庭,我火速辦了婚禮欧宜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘冗茸。我一直安慰自己,他們只是感情好豪诲,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布挂绰。 她就那樣靜靜地躺著,像睡著了一般交播。 火紅的嫁衣襯著肌膚如雪刹勃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天伍宦,我揣著相機與錄音乏梁,去河邊找鬼次洼。 笑死遇骑,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的亥啦。 我是一名探鬼主播练链,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼届吁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起疚沐,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤亮蛔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后尔邓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年灯节,在試婚紗的時候發(fā)現(xiàn)自己被綠了绵估。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡形入,死狀恐怖缝左,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情渺杉,我是刑警寧澤是越,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布倚评,位于F島的核電站天梧,受9級特大地震影響纯出,放射性物質(zhì)發(fā)生泄漏暂筝。R本人自食惡果不足惜焕襟,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一务漩、第九天 我趴在偏房一處隱蔽的房頂上張望饵骨。 院中可真熱鬧居触,春花似錦轮洋、人聲如沸抬旺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至床未,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間薇搁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工传货, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宏娄,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓粮宛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親巍杈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一词裤、總體內(nèi)容 1.1吼砂、協(xié)程的介紹 1.2鼎文、迭代器以及迭代器的應(yīng)用 1.3赖瞒、生成器(生成器與迭代器保存的都是生成數(shù)據(jù)...
    IIronMan閱讀 861評論 0 1
  • 當容器中的元素很多的時候蚤假,不可能全部讀取到內(nèi)存磷仰,那么就需要一種算法來推算下一個元素境蔼,這樣就不必創(chuàng)建很大的容器,生成...
    編程自習(xí)室閱讀 598評論 0 1
  • 迭代器 什么是迭代器 迭代器是指用 iter(可迭代對象) 函數(shù)返回的對象(實例) 迭代器可以用 next(it)...
    遇明不散閱讀 197評論 0 0
  • 更深入理解 Python 中的迭代 深入探討 Python 的 for 循環(huán)來看看它們在底層如何工作逢享,以及為什么它...
    lvyz0207閱讀 2,513評論 3 10
  • 文/鐵骨柔情 下雨的早上侧但,搭乘朋友家的車,送孩子上學(xué)柏锄$缘眨快到學(xué)校門口時,坐在副駕駛位置的我饶氏,習(xí)慣性的透過車窗向...
    鐵骨柔情青島閱讀 226評論 0 0