[Python學習]Iterator 和 Generator的學習心得

Iterator是迭代器的意思,它的做用是一次產生一個數據項,直到沒有爲止。這樣在 for 循環中就能夠對它進行循環處理了。那麼它與通常的序列類型(list, tuple等)有什麼區別呢?它一次只返回一個數據項,佔用更少的內存。但它須要記住當前的狀態,以便返回下一數據項。它是一個有着next()方法的對象。而序列類型則保存了全部的數據項,它們的訪問是經過索引進行的。node

使用Iterator的好處除了節省內存外,還有一個好處就是能夠把非線性化的處理轉換成線性化的方式來進行處理。如對一棵樹的訪問,傳統的方法可使用遞歸函數來處理,下面是對樹的一箇中序遍歷的示例:python

例1:

def deal_tree(node):
    if not node:
        return
    if node.leftnode:
        deal_tree(node.leftnode)
    process(node)
    if node.rightnode:
        deal_tree(node.rightnode)

deal_tree(root)函數

能夠看出,對結點的處理函數與遞歸函數是混在一塊兒的,不是很清晰。使用Iterator的方式改寫後爲:學習

例2:

1    def walk_tree(node):
2        if not node:
3            return
4        if node.leftnode:
5            for i in walk_tree(node.leftnode):
6                yield i
7        yield node
8        if node.rightnode:
9            for i in walk_tree(node.rightnode):
10               yield i
11
12   for node in wald_tree(root):
13       process(node)orm

生成結點的過程仍然是一個遞歸過程,但對於返回後的結點的處理就變成了線性化的處理,結構上要清晰多了。第5-6,9-10行要特別注意,若是不這樣處理直接調用walk_tree的話,其實返回的是一個Iterator對象,而不是想要的元素。對象

象上面的walk_tree函數在 Python 中能夠叫做Generator–產生器,它的做用是生成一個Iterator的對象。那麼它主要是將一個函數過程進行封裝,轉化爲Iterator對象,每執行到yield語句時,函數的狀態,數據都保存起來,而後返回相應的值。取下一個值的時候,再從上次運行的地方繼續運行,若是趕上yield語句,則再次保存狀態,返回結果,若是不存在值了,則自動引起一個異常StopIteration,從而Iterator再也不產生新的值。今後處咱們能夠了解,這裏的Iterator只能夠遍歷一次,但並不是全部的都是這樣,你徹底能夠對其進行控制。blog

下面我再介紹一下如何構造自已的Iterator。很簡單,建立一個類,知足Iterator的協議,也就是要定義__iter__方法,它返回一個Iterator對象,這個對象必須有next方法,所以咱們能夠總結出兩種對象模式:遞歸

class A:
    def __iter__(self):
        return self

    def next(self):
        if has_next_value(self):
            return next_value
        else:
            raise StopIteration索引

class B:
    def __iter__(self):
        return iterator_obj內存

A,B分別爲兩種對象模式(都是示例代碼)。模式A表示,在A中定義了next方法,所以__iter__簡單地返回自身便可。當不存在下一個值時,引起StopIteration異常。模式B表示,它使用了其它的Iterator對象,所以只須要定義__iter__便可,next不須要定義,由於返回的Iterator對象已經含有next方法了。若是是自已實現next方法,那麼在返回值以前須要記住當前的狀態,以便下一次運行時,能夠取下一個值。

第2個例子好象與這裏講的不同啊。這就是前面講的Generator,它的做用就是把一個函數轉換成一個Iterator,它自動保存狀態,中間數據,引起異常,所有是自動化了。並且它只能夠遍歷一次。若是想再次遍歷,只有從新生成新的Iterator對象才能夠。

在最新的 Python 2.4 版中新增了Genetaor Expression方式,它是用來生成簡單的,在函數調用須要序列參數時的一種Iterator寫法,語法就象是list comprehension的格式,如:

>>> sum(i*i for i in range(10))                 # sum of squares
285

不過這種寫法必需要在小括號對中,所以它的使用是有限的。它的目的主要是想更好的使用內存。

前面咱們提到不是全部的Iterator只能夠遍歷一次(使用Generator生成的只能遍歷一次),你徹底能夠控制它從新遍歷。好比咱們能夠在Iterator對象中增長一個復位方法,用來將內部的計數恢復到開始狀態,這樣咱們就能夠從新遍歷了。

下面咱們總結一下:

Iterator對象:具備__iter__方法,和next方法。當沒有新值時引起StopIteration異常。

Iterator的好處:在某些狀況下可使程序結構清晰,如將遞歸等非線性處理轉爲線性處理。能夠減小內存的佔用。

Generator:將一個函數轉化成Iterator對象的方法。使用它只須要在函數中須要返回值的時候調用yield語句。它是生成Iterator對象的簡單方法,只適用於函數。

相關文章
相關標籤/搜索