摘要:來說說迭代器和生成器,還有可迭代對象和生成器表達式。有點繞是不是,其實,一般只要知道可迭代對象以及它是如何實現的就行了,中常常用生成器來代替迭代器,可以說,生成器就是迭代器。
來說說迭代器和生成器,還有可迭代對象和生成器表達式。
之前簡單的提到過,一個對象是可迭代的可以理解為能夠使用for循環。這樣說其實不太準確,某個對象可迭代是因為它內部實現了$__iter__$這個特殊方法。比如在python中,序列類型(列表,元組這些)都是可以迭代的,因為內部都有$__iter__$方法的實現。
不過,其實我們不用特別的實現$__iter__$方法,只要實現了$__getitem__$方法就可以。這個方法我之前介紹過,實現它之后就可以進行切片以及迭代操作。為什么?因為在對一個對象迭代時如果找不到$__iter__$方法,python會自動去尋找$__getitem__$方法,然后構造一個迭代器,從0開始獲取元素。
說了半天,迭代器又是什么東西?可迭代對象,迭代器,這兩個是一樣的嗎?
迭代器是實現了$__next__$特殊方法的對象,而可迭代對象實現了$__iter__$方法,如果你需要迭代器能夠迭代自身,也需要實現$__iter__$方法。要注意的是,可迭代的對象必須實現$__iter__$方法,但不能實現 $__next__$ 方法。
在迭代器中實現了$__next__$方法,你就能使用next(data)來依次產出數據,如果此時沒有數據了,就會產生異常。像生孩子一樣,next一下生一個。
有點繞是不是,其實,一般只要知道可迭代對象以及它是如何實現的就行了,python 中常常用生成器來代替迭代器,可以說,生成器就是迭代器。因為生成器也實現了$__iter__$和$__next__$方法。
python中還有一個iter函數用來生成迭代器,比如把一個列表放進去,就可以使用next方法來一個個調用了。
說了這么多,來看個例子。
data = [1, 2, 3, 4] # data是列表,是個可迭代對象 # 使用循環迭代 for i, j in enumerate(data): print(i, j) # 生成一個迭代器 d = iter(data) # 調用next next(d) # 調用四次之后就會產生異常
0 1 1 2 2 3 3 4 1
我們來自己實現一個迭代器。
# 從后往前產出列表中的數據 class ReverseList: def __init__(self, item): #用range構造一個列表 self.list = list(range(item)) def __iter__(self): return self def __next__(self): try: return self.list.pop() except: raise StopIteration
用一下試試。
data = ReverseList(4) # 調用next,從后往前產出數據 print(next(data)) print(next(data)) print(next(data)) print(next(data)) # 如果繼續調用,會產生錯誤,因為沒有數據可產出了 print(next(data))
3 2 1 0 --------------------------------------------------------------------------- IndexError Traceback (most recent call last)in __next__(self) 12 try: ---> 13 return self.list.pop() 14 except: IndexError: pop from empty list During handling of the above exception, another exception occurred: StopIteration Traceback (most recent call last) in () 7 print(next(data)) 8 # 如果繼續調用,會產生錯誤,因為沒有數據可產出了 ----> 9 print(next(data)) in __next__(self) 13 return self.list.pop() 14 except: ---> 15 raise StopIteration StopIteration:
那什么又是生成器?
在程序設計中,內存是個很寶貴的東西,占用太多的內存總是不好的,生成器的作用就是我先把你的數據表示出來,但是實際上并不占用內存空間,只有在你調用它時才會占用。一般情況下,比如你定義了一個列表,會自動的使用一段內存空間。
在 python中,只要定義了yield關鍵字的函數就是生成器。上面說了,生成器就是迭代器,你可以進行迭代操作(循環),調用next來一個個產出數據。
def gen123(): yield 1 yield 2 yield 3 for i in gen123(): print(i) g = gen123() print(next(g))
1 2 3 1
雖然說生成器就是迭代器,但是在python的定義中,迭代器用來遍歷集合,從中產出元素,而生成器無需遍歷集合就能生成值,比如range()函數,生成器不僅能夠產出集合中的元素,還可以產出派生自元素的其他值。
我在上一篇文章(Python奇遇記:數據結構窺探2)中提到過生成器表達式,只介紹了一下它的用法,那么生成器表達式是什么東西?
其實,生成器表達式就是生成器的快速實現而已,類似于之前講過的具名元組。有些時候需要快速的生成一段數據,使用生成器表達式即可,無需定義函數再調用。
本人才疏學淺,上文中難免有些錯誤,還請各位品評指正。如果覺得寫的還行,歡迎關注我的公眾號MLGroup,帶你走進機器學習的世界。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/44531.html
摘要:擠掉了堆中實現了堆排序。你可以用堆排序來查找一個序列中最大的或者最小的幾個元素。除了使用堆排序,中還有排序和,這兩個排序最終生成以列表表示的排序結果,堆排序也是。 這次我們來說說python中的數據結構。當然了,不會講很基礎的內容。 用過python的都知道,python有著與其他語言很不一樣的數據類型,像什么列表、元組、集合、字典之類。這些數據類型造就了python簡單易用同時又很強...
摘要:找出列表中小于的數據除了列表推導式,還有字典推導式,集合推導式,用法都一樣。如果你的數據量很大的話,考慮使用生成器表達式。切片不僅對列表有用,同樣適用于元組和字符串。切片命名使用方法,內部參數與切片一樣。對剩余的的數據,使用星號代替即可。 上次我們講了幾個不常見的數據類型,每個都有自己特殊的用途,雖然不經常用到,了解一下也好。比如我們提到的數組類型,如果在數據量很大的時候同時要效率,就...
摘要:在中,特殊方法以雙下劃線開始,以雙下劃線結束。真假值,如果向量模為,返回實現向量加法實現向量乘法,例如返回向量的模返回歐幾里德范數找個例子運行下。怎么辦中有個特殊方法,可以修改控制臺輸出的樣式。 什么是特殊方法?當我們在設計一個類的時候,python中有一個用于初始化的方法$__init__$,類似于java中的構造器,這個就是特殊方法,也叫作魔術方法。簡單來說,特殊方法可以給你設計的...
摘要:協程的歷史說來話長,要從生成器開始講起。我們可以使用把數據發送給協程函數。可以看到,在第次接收完數據之后,會產生結束的異常,因為程序流程結束了,這是正常現象。在這個階段,協程本質上還是由生成器構成的。所以,協程的介紹到這里就結束啦。 在上一篇對python并發編程的理解 中,我簡單提到了協程的概念,有一個錯誤需要指出的是,asyncio不全是對協程的實現,只是用到了協程。 協程的歷史說...
摘要:字典和集合都是基于散列表實現的,散列表也就是表,了解過數據結構的應該知道。而使用另一種辦法,任何鍵在找不到的情況下都會用中的值數據類型比如替換。在設計時就可以使用創建你的數據接口。 這次主要說說字典和集合這兩種數據類型。 字典和集合都是基于散列表實現的,散列表也就是hash表,了解過數據結構的應該知道。與散列表相關的一個概念叫做可散列,什么是可散列?在python官方定義中是這樣說的:...
閱讀 854·2023-04-26 00:11
閱讀 2655·2021-11-04 16:13
閱讀 2101·2021-09-09 09:33
閱讀 1470·2021-08-20 09:35
閱讀 3816·2021-08-09 13:42
閱讀 3603·2019-08-30 15:55
閱讀 1037·2019-08-30 15:55
閱讀 2218·2019-08-30 13:55