對數學家來說,Python這門語言有著很多吸引他們的地方。舉幾個例子:對于tuple、lists以及sets等容器的支持,使用與傳統數學類似的符號標記方式,還有列表推導式這樣與數學中集合推導式和集的結構式(set-builder notation)很相似的語法結構。
另外一些很吸引數學愛好者的特性是Python中的iterator(迭代器)、generator(生成器)以及相關的itertools包。這些工具幫助人們能夠很輕松的寫出處理諸如無窮序列(infinite sequence)、隨機過程(stochastic processes)、遞推關系(recurrence relations)以及組合結構(combinatorial structures)等數學對象的優雅代碼。本文將涵蓋我關于迭代器和生成器的一些筆記,并且有一些我在學習過程中積累的相關經驗。
Iterators
迭代器(Iterator)是一個可以對集合進行迭代訪問的對象。通過這種方式不需要將集合全部載入內存中,也正因如此,這種集合元素幾乎可以是無限的。你可以在Python官方文檔的“迭代器類型(Iterator Type)”部分找到相關文檔。
讓我們對定義的描述再準確些,如果一個對象定義了__iter__方法,并且此方法需要返回一個迭代器,那么這個對象就是可迭代的(iterable)。而迭代器是指實現了__iter__以及next(在Python 3中為__next__)兩個方法的對象,前者返回一個迭代器對象,而后者返回迭代過程的下一個集合元素。據我所知,迭代器總是在__iter__方法中簡單的返回自己(self),因為它們正是自己的迭代器。
一般來說,你應該避免直接調用__iter__以及next方法。而應該使用for或是列表推導式(list comprehension),這樣的話Python能夠自動為你調用這兩個方法。如果你需要手動調用它們,請使用Python的內建函數iter以及next,并且把目標迭代器對象或是集合對象當做參數傳遞給它們。舉個例子,如果c是一個可迭代對象,那么你可以使用iter(c)來訪問,而不是c.__iter__(),類似的,如果a是一個迭代器對象,那么請使用next(a)而不是a.next()來訪問下一個元素。與之相類似的還有len的用法。
說到len,值得注意的是對迭代器而言沒必要去糾結length的定義。所以它們通常不會去實現__len__方法。如果你需要計算容器的長度,那么必須得手動計算,或者使用sum。本文末,在itertools模塊之后會給出一個例子。
有一些可迭代對象并不是迭代器,而是使用其他對象作為迭代器。舉個例子,list對象是一個可迭代對象,但并不是一個迭代器(它實現了__iter__但并未實現next)。通過下面的例子你可以看到list是如何使用迭代器listiterator的。同時值得注意的是list很好地定義了length屬性,而listiterator卻沒有。
>>> a = [1, 2]>>> type(a)<type 'list'>>>> type(iter(a))<type 'listiterator'>>>> it = iter(a)>>> next(it)1>>> next(it)2>>> next(it)Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration>>> len(a)2>>> len(it)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: object of type 'listiterator' has no len()
|
新聞熱點
疑難解答