Python可迭代對象,迭代器,產生器的區別__Python

來源:互聯網
上載者:User
本篇文章簡單談談可迭代對象,迭代器和產生器之間的關係。



三者簡要關係圖





可迭代對象與迭代器


剛開始我認為這兩者是等同的,但後來發現並不是這樣;下面直接拋出結論: 1)可迭代對象包含迭代器。
2)如果一個對象擁有__iter__方法,其是可迭代對象;如果一個對象擁有next方法,其是迭代器。
3)定義可迭代對象,必須實現__iter__方法;定義迭代器,必須實現__iter__和next方法。


你也許會問,結論3與結論2是不是有一點矛盾。既然一個對象擁有了next方法就是迭代器,那為什麼迭代器必須同時實現兩方法呢。 因為結論1,迭代器也是可迭代對象,因此迭代器必須也實現__iter__方法。

介紹一下上面涉及到的兩個方法:

1)__iter__()

該方法返回的是當前對象的迭代器類的執行個體。因為可迭代對象與迭代器都要實現這個方法,因此有以下兩種寫法。

寫法一:用於可迭代對象類的寫法,返回該可迭代對象的迭代器類的執行個體。

寫法二:用於迭代器類的寫法,直接返回self(即自己本身),表示自身即是自己的迭代器。

也許有點暈,沒關係,下面會給出兩寫法的例子,我們結合具體例子看。


2)next()

返回迭代的每一步,實現該方法時注意要最後超出邊界要拋出StopIteration異常。


下面舉個可迭代對象與迭代器的例子:

#!/usr/bin/env python# coding=utf-8class MyList(object):            # 定義可迭代對象類    def __init__(self, num):        self.data = num          # 上邊界    def __iter__(self):        return MyListIterator(self.data)  # 返回該可迭代對象的迭代器類的執行個體class MyListIterator(object):    # 定義迭代器類,其是MyList可迭代對象的迭代器類    def __init__(self, data):        self.data = data         # 上邊界        self.now = 0             # 當前迭代值,初始為0    def __iter__(self):        return self              # 返回該對象的迭代器類的執行個體;因為自己就是迭代器,所以返回self    def next(self):              # 迭代器類必須實現的方法        while self.now < self.data:            self.now += 1            return self.now - 1  # 返回當前迭代值        raise StopIteration      # 超出上邊界,拋出異常my_list = MyList(5)              # 得到一個可迭代對象print type(my_list)              # 返回該對象的類型my_list_iter = iter(my_list)     # 得到該對象的迭代器執行個體,iter函數在下面會詳細解釋print type(my_list_iter)for i in my_list:                # 迭代    print i

運行結果:



問題:上面的例子中出現了iter函數,這是什麼東西。和__iter__方法有關係嗎。
其實該函數與迭代是息息相關的,通過在Python命令列中列印“help(iter)”得知其有以下兩種用法。

用法一:iter(callable, sentinel)
不停的調用callable,直至其的傳回值等於sentinel。其中的callable可以是函數,方法或實現了__call__方法的執行個體。

用法二:iter(collection)
1)用於返回collection對象的迭代器執行個體,這裡的collection我認為表示的是可迭代對象,即該對象必須實現__iter__方法; 事實上iter函數與__iter__方法聯絡非常緊密,iter()是直接調用該對象的__iter__(),並把__iter__()的返回結果作為自己的傳回值,故該用法常被稱為“建立迭代器”。
2)iter函數可以顯示調用,或當執行“for i in obj:”,Python解譯器會在第一次迭代時自動調用iter(obj),之後的迭代會調用迭代器的next方法,for語句會自動處理最後拋出的StopIteration異常。


通過上面的例子,相信對可迭代對象與迭代器有了更具體的認識,那麼產生器與它們有什麼關係呢。下面簡單談一談



產生器


產生器是一種特殊的迭代器,產生器自動實現了“迭代器協議”(即__iter__和next方法),不需要再手動實現兩方法。

產生器在迭代的過程中可以改變當前迭代值,而修改普通迭代器的當前迭代值往往會發生異常,影響程式的執行。


看一個產生器的例子:

#!/usr/bin/env python# coding=utf-8def myList(num):      # 定義產生器    now = 0           # 當前迭代值,初始為0    while now < num:        val = (yield now)                      # 返回當前迭代值,並接受可能的send發送值;yield在下面會解釋        now = now + 1 if val is None else val  # val為None,迭代值自增1,否則重新設定當前迭代值為valmy_list = myList(5)   # 得到一個產生器對象print my_list.next()  # 返回當前迭代值print my_list.next()my_list.send(3)       # 重新設定當前的迭代值print my_list.next()print dir(my_list)    # 返回該對象所擁有的方法名,可以看到__iter__與next在其中

運行結果:



具有yield關鍵字的函數都是產生器,yield可以理解為return,返回後面的值給調用者。不同的是return返回後,函數會釋放,而產生器則不會。在直接調用next方法或用for語句進行下一次迭代時,產生器會從yield下一句開始執行,直至遇到下一個yield。



參考資料:

Python核心編程第二版11.10節,13.13.3節

完全理解Python迭代對象、迭代器、產生器

深入講解Python中的迭代器和產生器

如何更好地理解Python迭代器和產生器


文中如有不恰當的地方,還望包容和指出,感謝


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.