Python編程中實現迭代器的一些技巧小結

來源:互聯網
上載者:User
yield實現迭代器
如引言中的描述,實現一個可迭代的功能要是每次都手動實現iter,next稍稍有點麻煩,所需的代碼也是比較客觀。在python中也能通過藉助yield的方式來實現一個迭代器。yield有一個關鍵的作能,它能夠中斷當前的執行邏輯,保持住現場(各種值的狀態,執行的位置等等),返回相應的值,下一次執行的時候能夠無縫的接著上次的地方繼續執行,如此迴圈反覆知道滿足事先設定的允出準則或者發生錯誤強制被中斷。
其具體功能是可以當return使用,從函數裡返回一個值,不同之處是用yield返回之後,可以讓函數從上回yield返回的地點繼續執行。也就是說,yield返回函數,交給調用者一個傳回值,然後再“瞬移”回去,讓函數繼續運行, 直到嚇一跳yield語句再返回一個新的值。使用yield返回後,調用者實際得到的是一個迭代器對象,迭代器的值就是傳回值,而調用該迭代器的next()方法會導致該函數恢複yield語句的執行環境繼續往下跑,直到遇到下一個yield為止,如果遇不到yield,就會拋出異常表示迭代結束。
看一個例子:

>>> def test_yield():... yield 1... yield 2... yield (1,2)...>>> a = test_yield()>>> a.next()1>>> a.next()2>>> a.next()(1, 2)>>> a.next()Traceback (most recent call last): File "", line 1, in ?StopIteration

光聽描述就覺得和迭代器的工作方式很一致是吧,的確,yield能把它所在的函索變成一個迭代器,拿最經典的菲波那切數列的例子聊簡述一下工作的方式:

def fab(max):  n, a, b = 0, 0, 1  while n < max: print b, "is generated"  yield b a, b = b, a + b  n = n + 1 >>> for item in fab(5):... print item... 1 is generated11 is generated12 is generated23 is generated35 is generated5

我們有回想一下for關鍵字的文法糖,在這裡遍曆5以內的菲波那切數列值的時候,很顯然fab(5)產生了一個可迭代的對象,遍曆開始的時候它的iter方法被調用返回一個實際工作的迭代器對象,然後每一次調用它的next方法返回一個菲波那切數列值然後列印出來。
我們可以將調用產生器函數返回的對象的屬性列印出來,看一下到底發生了什麼:

>>> temp_gen = fab(5)>>> dir(temp_gen)['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']

正如上面的描述,單純調用fab並不會讓函數立刻開始返回任何值,並且從列印出的fab(5)的屬性列表能夠看到,產生器函數返回的對象包含有__iter__,next的實現。與我們手動實現相比,使用yield很方便的就能夠實現我們想要的功能,代碼量縮減不少。

Generator Expression
python中另一種能更優雅產生迭代器對象的方式就是使用產生器運算式Generator expression,它和列表解析運算式有著非常相似的寫法,僅僅是把中括弧[]變成()而已,不過小小改變產生的實際效果確實大大的不一樣:

>>> temp_gen = (x for x in range(5))>>> temp_gen at 0x7192d8>>>> for item in temp_gen:... print item... 01234>>> dir(temp_gen)['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']

看過上面對yield的描述,這個例子以及對應的輸出日誌還是相當直接明了的,無論是temp_gen的列印日誌描述,for語句遍曆的輸出結果還是調用dir輸出的屬性列表,都赤裸裸的表明產生器運算式確實產生了能夠支援迭代的對象。另外運算式裡面也能夠調用函數,增加適量的過濾條件。

內建庫itertools 和 iter
python內建的庫itertools提供了大量的工具方法,這些方法能夠協助我們建立能進行高效遍曆和迭代的對象,裡麵包含不少有意思並且有用的方法,比如像chain, izip/izip_longest, combinations, ifilter等等。在python中還有一個內建的iter函數非常有用,能夠返回一個迭代器對象,之後也就能夠進行可以查看對應的協助文檔簡單看一下:

>>> iter('abc')>>> str_iterator = iter('abc')>>> next(str_iterator)'a'>>> next(str_iterator)'b'>>> lst_gen = iter([1,2,3,4])>>> lst_gen>>> dir(lst_gen)['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__length_hint__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'next']>>> help(iter)Help on built-in function iter in module builtins:iter(...) iter(iterable) -> iterator iter(callable, sentinel) -> iterator Get an iterator from an object. In the first form, the argument must supply its own iterator, or be a sequence. In the second form, the callable is called until it returns the sentinel.
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.