天天看點

詳解生成器、疊代器

  要搞清楚什麼關于疊代器,生成器,可疊代對象,前提是我們要了解何為疊代。

  第一,疊代需要重複進行某一操作

  第二,本次疊代的要依賴上一次的結果繼續往下做,如果中途有任何停頓,都不能算是疊代.

  下面來看看幾個例子,你就會更能了解疊代的含義。

  例子1,僅僅隻是在重複一件事,那就是不停的列印"hello world",并且,這個列印的結果并不依賴上一次輸出的值。而例子2,就很好地說明疊代的含義,重複+繼續。

  按照上面疊代的含義,我們應該能夠知道何為可疊代對象。顧名思義,就是一個對象能夠被疊代的使用。那麼我們該如何判斷一個對象是否可疊代呢?

  Python提供了子產品collections,其中有一個isinstance(obj,string)的函數,可以判斷一個對象是否為可疊代對象。看下面執行個體:

  由上面得出,除了整型之外,python内的基本資料類型都是可疊代對象,包括檔案對象。那麼,python内部是如何知道一個對象是否為可疊代對象呢?答案是,在每一種資料類型對象中,都會有有一個__iter__()方法,正是因為這個方法,才使得這些基本資料類型變為可疊代。 

  如果不信,我們可以來看看下面代碼片段:

檢測屬性方法

  如果大家還是不信,可以繼續來測試。我們自己來寫一個類,看看有__iter__()方法和沒有此方法的差別。

View Code

  從上面,實驗結果可以看出一個對象是否可疊代,關鍵看這個對象是否有__iter__()方法。

  在介紹疊代器之前,我們先來了解一下容器這個概念。

  容器是一種把多個元素組織在一起的資料結構,容器中的元素可以逐個地疊代擷取。簡單來說,就好比一個盒子,我們可以往裡面存放資料,也可以從裡面一個一個地取出資料。

  在python中,屬于容器類型地有:list,dict,set,str,tuple.....。容器僅僅隻是用來存放資料的,我們平常看到的 l = [1,2,3,4]等等,好像我們可以直接從清單這個容器中取出元素,但事實上容器并不提供這種能力,而是可疊代對象賦予了容器這種能力。

  說完了容器,我們在來談談疊代器。疊代器與可疊代對象差別在于:__next__()方法。

  我們可以采用以下方法來驗證一下:

  結果顯示:除了檔案對象為疊代器,其餘均不是疊代器

  下面,我們進一步來驗證一下:

  從輸出結果可以表明,疊代器與可疊代對象僅僅就是__next__()方法的有無。

  先來看看一段普通的疊代過程:

   根據之前的分析,我們知道 l = [1,2,3,4,5]是一個可疊代對象。而且可疊代對象是不可以直接從其中取到元素。那麼為啥我們還能從清單L中取到元素呢?這一切都是因為for循環内部實作。在for循環内部,首先L會調用__iter__()方法,将清單L變為一個疊代器,然後這個疊代器再調用其__next__()方法,傳回取到的第一個值,這個元素就被指派給了i,接着就列印輸出了。

  下面,我們通過一系列的實驗來證明上述所說的。

  上述實驗,與我上面說明的一緻。  

  下面,我們可以while循環來模拟for循環,輸出清單中的元素。

  由上分析,我們可以總結出:當我們試圖用for循環來疊代一個可疊代對象時候,for循環在内部進行了兩步操作:第一,将可疊代對象S變為疊代器M;第二,疊代器M調用__next__()方法,并且傳回其取出的元素給變量i。

  

詳解生成器、疊代器

  你可能看見過這種寫法,for i in iter(M):xxx ,其實這一步操作和我們上面沒什麼差別。iter()函數,就是将一個可疊代對象M變為疊代器也就是M調用__iter__()方法,然後内部在調用__next__()方法。也就是說,

  還有next(M)等價于M.__next__。  

    1.節約記憶體

    2.不依賴索引取值

    3.實作惰性計算(什麼時候需要,在取值出來計算)

  什麼是生成器?可以了解為一種資料類型,這種資料類型自動實作了疊代器協定(其他的資料類型需要調用自己内置的__iter__方法)。

  按照我們之前所說的,疊代器必須滿足兩個條件:既有__iter__(),又有__next__()方法。那麼生成器是否也有這兩個方法呢?答案是,YES。具體來通過以下代碼來看看。

  實驗表明,生成器就是疊代器。

  Python有兩種不同的方式提供生成器:

    1.生成器函數(函數内部有yield關鍵字):正常函數定義,但是,使用yield語句而不是return語句傳回結果。yield語句一次傳回一個結果,在每個結果中間,挂起函數的狀态,以便下次重它離開的地方繼續執行

    2.生成器表達式:類似于清單推導,但是,生成器傳回按需産生結果的一個對象,而不是一次建構一個結果清單

  既然生成器就是疊代器,那麼我們是不是也可以通過for循環來周遊出生成器中的内容呢?看下面代碼.

  很顯然,生成器也可以通過for循環來周遊出其中的内容。

  下面我們來看看生成器函數執行流程:

  每次調用g.__next__()就回去函數内部找yield關鍵字,如果找得到就輸出yield後面的值并且傳回;如果沒有找到,就會報出異常。上述代碼中如果在調用g.__next__()就會報錯。

  Python使用生成器對延遲操作提供了支援。所謂延遲操作,是指在需要的時候才産生結果,而不是立即産生結果。這也是生成器的主要好處。

執行個體:生成器模拟Linux下tail -f a.txt | grep 'error' | grep '404'

  生成器小結:

    1.是可疊代對象

    2.實作了延遲計算,省記憶體啊

    3.生成器本質和其他的資料類型一樣,都是實作了疊代器協定,隻不過生成器附加了一個延遲計算省記憶體的好處,其餘的可疊代對象可沒有這點好處!

詳解生成器、疊代器

本文轉自xsster51CTO部落格,原文連結: http://blog.51cto.com/12945177/1950814,如需轉載請自行聯系原作者