天天看點

4.python的疊代器與生成器

一.什麼玩意是疊代器?

先說說什麼是疊代吧,疊代就是一件事情重複很多次,比如說for循環。

for循環可以對一切有__iter__方法的對象進行疊代,那麼什麼是__iter__方法呢?

一個對象是否可疊代,全都取決于這個對象是否有__iter__方法,調用對象的__iter__方法,就回傳回一個疊代器,這個疊代器一定具有next方法,在調用這個疊代器的next方法時,疊代器就回傳回它的下一個值,當疊代器中沒有值可以傳回了,就回抛出一個名為StopIteration的異常,停止疊代。

疊代器還有個很重要的特性,就是不可逆,隻能前進,不能後退。

for循環就是這樣工作的,for循環在循環一個對象的時候,會調用這個對象的__iter__方法,得到疊代器,然後在調用這個疊代器的next方法,去獲得這個疊代器中包涵的每個值。

二.清單和疊代器的差別在哪裡?如何可以實作一個基本的疊代器?

疊代器的工作方式,是在使用的時候計算一個值擷取一個值,而清單呢,是一次性擷取所有的值,如果有很多值,就會占用很大的記憶體。

當自己建立一個對象時,如何讓自己的對象可疊代?

class test_class:

    def __init__(self,start_num,stop_num):

        self.start_num = start_num

        self.stop_num = stop_num

    def next(self):

        if self.start_num <  self.stop_num:

            self.start_num += 1

        return self.start_num

    def __iter__(self):

        return self

test_obj = test_class(0,3)

print test_obj.next()

>>>1

>>>2

>>>3

三.什麼是生成器?

個人的了解,生成器是個比較特殊的可疊代對象,它與其他的可疊代對象不太一樣的地方,就是,其他的可疊代對象需要調用__iter__方法,傳回個疊代器對象,然後通過疊代器對象去執行next方法,擷取疊代器中的值,但是生成器直接可以被疊代,無需執行__iter__方法。

在python中生成器有兩種表達形式:

函數式生成器:也就是字面意思,在正常的函數中定義的生成器,語句的傳回值不再使用return去傳回,而是使用yield關鍵字每次傳回一個結果,一個函數中不可以有多個return,但是可以有多個yield,函數中的每一個yield都會傳回一個結果,每執行一個yield,函數的執行狀态都會被‘挂起’可以了解為暫停,下次繼續調用這個函數的時候,會從上次挂起的位置繼續向下執行。

下面是關于函數式生成器的例子:

下面這個例子驗證了yield的兩種特性,第一種是一個函數可以yield多個值,有多個yield,另外一個就是函數式生成器的挂起特性。

def func1():

    yield 1

    print "第一個yield執行完成~"

    yield 2

    print "第二個yield執行完成~"

    yield 3

    print "第三個yield執行完成~"

for i in func1():

    print i

       第一個yield執行完成~

      2

       第二個yield執行完成~

      3

       第三個yield執行完成~

生成器表達式:使用類似于清單推導式的方法,但是傳回的對象不再是一個清單,而是一個可以按需生成結果的一個對象(生成器)。

       例1:

        for i in (i for i in range(10000)):

            print i

(i for i in range(5)) 這個就是生成器表達式。

(i for i in range(10000)) =  def test(): for i in range(10000):yield i

這兩個種寫法起到的作用是一樣的,隻不過是寫法不同,一個是生成器表達式,另一種是函數式生成器。

有沒有覺得這種生成器表達式和清單推導式看起來很像,不同的地方就在于清單推導式是使用[]中括号,而生成器表達式使用的是()小括号?

事實就是如此,它們之間的文法确實隻差一個括号,但是,生成器表達式更節省記憶體空間。

關于生成器,大緻就說的差不多了,最後來個總結:

生成器的定義方法與普通的函數是一模一樣的,不同的地方就是生成器使用yield傳回一個值,函數使用return傳回一個值。

在python中,生成器會自動實作疊代協定,在沒有值可以傳回的時候,傳回一個StopIteration異常。

生成器使用yield語句傳回一個值。yield語句挂起該生成器函數的狀态,保留足夠的資訊,以便之後從它離開的地方繼續執行。

下面的例子是清單推導式和生成器表達式執行的效率對比,感興趣的小夥伴可以在自己電腦上執行一下試試。

#清單解析

sum([i for i in range(100000000)])#記憶體占用大,機器容易卡死

#生成器表達式

sum(i for i in range(100000000))#幾乎不占記憶體

      本文轉自蘇浩智 51CTO部落格,原文連結:http://blog.51cto.com/suhaozhi/1908913,如需轉載請自行聯系原作者