国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

淺談Python中的可迭代對象、迭代器、For循環工作機制、生成器

2020-01-04 13:36:07
字體:
來源:轉載
供稿:網友

1.iterable iterator區別

要了解兩者區別,先要了解一下迭代器協議:
迭代器協議是指:對象需要提供__next__()方法,它返回迭代中的元素,在沒有更多元素后,拋出StopIteration異常,終止迭代。
可迭代對象就是:實現了迭代器協議的對象。
協議是一種約定,可迭代對象實現迭代器協議,Python的內置工具(如for循環,sum,min,max函數等)通過迭代器協議訪問對象,因此,for循環并不需要知道對象具體是什么,只需要知道對象能夠實現迭代器協議即可。
迭代器(iterator)與可迭代對象(iterable)并不是同一個概念。

直觀上:

1.可迭代對象(iterable):凡是具有__iter__的方法的類,都是可迭代的類。可迭代類創建的對象實現了__iter__方法,因此就是可迭代對象。用list、tuple等容器創建的對象,都是可迭代對象。可迭代對象通過__iter__方法返回一個迭代器,然后在內部調用__next__方法進行迭代,最后沒有元素時,拋出異常(這個異常python自己會處理,不會讓開發者看見)。

2.迭代器(iterator):迭代器對象必須同時實現__iter__和__next__方法才是迭代器。對于迭代器來說,__iter__ 返回的是它自身 self,__next__ 則是返回迭代器中的下一個值,最后沒有元素時,拋出異常(異常可以被開發者看到)。

從上面2點可以看出:

1.迭代器一定是可迭代對象,因為它實現了__iter__()方法;

2.通過iter()方法(在類的內部就是__iter__)能夠使一個可迭代對象返回一個迭代器。

3.迭代器的 __iter__ 方法返回的是自身,并不產生新的迭代器對象。而可迭代對象的 __iter__ 方法通常會返回一個新的迭代器對象。

第3點性質正是可迭代對象可以重復遍歷的原因(每次返回一個獨立的迭代器,就可以保證不同的迭代過程不會互相影響);而迭代器由于返回自身,因此只能遍歷一次。

上面3點可以通過下面的例子看出來:

from collections import Iterablefrom collections import Iteratorprint isinstance(iter([1,2]),Iterator)print isinstance(iter([1,2]),Iterable)print isinstance([1,2],Iterator)print isinstance([1,2],Iterable)##resultTrueTrueFalseTrue##id可以查看一個對象在內存中的地址test=[1,2,3]testIter=iter(test)print id(testIter)print id(testIter)print id(iter(test))print id(iter(test))print id(test.__iter__())print id(test.__iter__())##result:可迭代對象每次調用iter方法都會返回一個新的迭代器對象,而迭代器對象調用iter方法返回自身67162576 67162576 67162688 67162632 67162856 67163024

2.iterable的工作機制

拿一個例子看看,首先定義一個有__iter__方法,但是沒有next()方法的類 (PS:在python2中是next(),python3是__next__()):

from collections import Iterable, Iteratorclass Student(object): def __init__(self,score): self.score=score def __iter__(self): return iter(self.score) test= Student([80,90,95])print isinstance(test, Iterable)print isinstance(test, Iterator)for i in test: print i##resultTrueFalse809095##可重復遍歷for i in test: print i##result809095

上面代碼的結果印證了定義中提到的:

缺少了next()方法,可迭代對象就不是迭代器。

此外,注意到:可迭代對象通過__iter__方法每次都返回了一個獨立的迭代器,這樣就可以保證不同的迭代過程不會互相影響。

也就是說,通過iterable可以實現重復遍歷,而迭代器是無法重復遍歷的!

因此,如果想要把可迭代對象轉變為迭代器,可以先調用iter()方法返回一個迭代器。然后就可以用next()不斷迭代了!

print isinstance(iter(test),Iterator)testIter=iter(test)print testIter.next()print testIter.next()print testIter.next()##resultTrue809095##一旦取完了可迭代對象中所有的元素,再次調用next就會發生異常print testIter.next()##resultStopIteration: 

3.迭代器Iterator的工作機制

看下面這個例子:

class Student(object): def __init__(self,score): self.score=score def __iter__(self): return self  def next(self): if self.score<100: self.score+=1 return self.score else: raise StopIteration() test= Student(90)print isinstance(test, Iterable)print isinstance(test, Iterator)print test.next()print test.next()print test.next()for i in test: print i##resultTrueTrue919293949596979899100##如果此時再對test這個迭代器調用next方法,就會拋出異常test.next()##resultStopIteration: 

這個例子印證了定義中的:迭代器對象必須同時實現__iter__和__next__方法才是迭代器。

那么,使用迭代器好處在哪呢?

Python的Iterator對象表示的是一個數據流,Iterator對象可以被next()函數調用并不斷返回下一個數據,直到沒有數據時拋出StopIteration錯誤。可以把這個數據流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()函數實現按需計算下一個數據,所以Iterator的計算是惰性的,只有在需要返回下一個數據時它才會計算。

一個很常見的應用就是:Python在處理列表的時候,是直接把整個列表讀進內存的,當遇到大量樣本時的時候會變得很慢。而迭代器的優勢在于只把需要的元素讀進內存,因此占用內存更少。

換句話說,迭代器是一種惰性求值模式,它是有狀態的,只有在調用時才返回值,沒有調用的時候就等待下一次調用。這樣就節省了大量內存空間。

這個例子印證了定義中的:迭代器對象必須同時實現__iter__和__next__方法才是迭代器。

那么,使用迭代器好處在哪呢?

Python的Iterator對象表示的是一個數據流,Iterator對象可以被next()函數調用并不斷返回下一個數據,直到沒有數據時拋出StopIteration錯誤。可以把這個數據流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()函數實現按需計算下一個數據,所以Iterator的計算是惰性的,只有在需要返回下一個數據時它才會計算。

一個很常見的應用就是:Python在處理列表的時候,是直接把整個列表讀進內存的,當遇到大量樣本時的時候會變得很慢。而迭代器的優勢在于只把需要的元素讀進內存,因此占用內存更少。

換句話說,迭代器是一種惰性求值模式,它是有狀態的,只有在調用時才返回值,沒有調用的時候就等待下一次調用。這樣就節省了大量內存空間。

4.for循環的工作機制

有了上面2個例子,就可以總結一下在可迭代對象與迭代器中的For循環工作機制了。

當對象本身就是迭代器時,For循環工作機制:

  1. 調用 __iter__方法,返回自身self,也就是返回迭代器。
  2. 不斷地調用迭代器的next()方法,每次按序返回迭代器中的一個值。
  3. 迭代到最后沒有元素時,就拋出異常 StopIteration

在可迭代對象中,for循環工作機制:

  1. 先判斷對象是否為可迭代對象(等價于判斷有沒有__iter__或__getitem__方法),沒有的話直接報錯,拋出TypeError異常。有的話,調用 __iter__方法,返回一個迭代器。
  2. 在python內部不斷地調用迭代器的__next__方法,每次按序返回迭代器中的一個值。
  3. 迭代到最后沒有元素時,就拋出異常 StopIteration,這個異常 python 自己會處理,不會暴露給開發者。

借用網絡上的一張圖直觀理解一下:

Python,可迭代對象,迭代器,For循環工作機制,生成器

此外,還要注意,python中的for循環其實兼容了兩種機制:

  1. 如果對象有__iter__會返回一個迭代器。
  2. 如果對象沒有__iter__,但是實現了__getitem__,會改用下標迭代的方式。
  3. __getitem__可以幫助一個對象進行取數和切片操作。

當for發現沒有__iter__但是有__getitem__的時候,會從0開始依次讀取相應的下標,直到發生IndexError為止,這是一種舊的迭代協議。iter方法也會處理這種情況,在不存在__iter__的時候,返回一個下標迭代的iterator對象來代替。一個重要的例子是str,字符串就是沒有__iter__方法的,但是卻依然可以迭代,原因就是其在for循環時調用了__getitem__方法。

看一個例子:

from collections import Iterable, Iteratorclass Student(object): def __init__(self,score): self.score=score def __getitem__(self,n): return self.score[n] test= Student([80,90,95])print isinstance(test, Iterable)print isinstance(test, Iterator)print isinstance(iter(test), Iterable)print isinstance(iter(test), Iterator)for i in test: print i##resultFalseFalseTrueTrue809095for i in range(0,3): print test[i]##result809095for i in iter(test): print i##result809095

可以看到,實現了__getitem__方法的對象本身,盡管不是iterable與iterator,仍舊是可以調用for循環的。
通過iter方法,返回一個下標迭代的iterator對象。

5.generator的原理

最后說一下生成器,生成器是一種特殊的迭代器,當然也是可迭代對象。
對于生成器,Python會自動實現迭代器協議,以便應用到迭代中(如for循環,sum函數)。由于生成器自動實現了迭代器協議,所以,我們可以調用它的next方法,并且,在沒有值可以返回的時候,生成器自動產生StopIteration異常。
創建生成器的方法:將return 改為yield。具體的實現網絡上教程很多,不細說了。

6.總結

到一幅圖片很好的描述了本文的所有內容,就拿它作為文末的總結吧!

Python,可迭代對象,迭代器,For循環工作機制,生成器

以上所述是小編給大家介紹的Python中的可迭代對象、迭代器、For循環工作機制、生成器詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VEVB武林網網站的支持!


注:相關教程知識閱讀請移步到python教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 芜湖县| 富顺县| 福安市| 花莲县| 石林| 永福县| 洛浦县| 莱西市| 思南县| 南开区| 湖口县| 东至县| 珲春市| 滕州市| 延庆县| 崇州市| 淮阳县| 九台市| 静海县| 靖安县| 雷山县| 青冈县| 油尖旺区| 六枝特区| 博乐市| 杭锦旗| 雷州市| 镇宁| 富蕴县| 黄大仙区| 山东省| 台北市| 东至县| 灵宝市| 新丰县| 铜川市| 汉中市| 上蔡县| 鄢陵县| 开鲁县| 大石桥市|