class mylist(object): def __init__(self,num): self.num = num self.list = [num+1,num+2,num+3] def __iter__(self): return mylistiterator(self.list) class mylistiterator(object): def __init__(self,data): self.data = data self.now = 0 def __iter__(self): return self def __next__(self): while self.now<len(self.data): self.now += 1 return self.data[self.now-1] raise StopIteration my_list = mylist(5) print(type(my_list)) for i in my_list: print(i)
打印結果:python
def 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,不然從新設定當前迭代值爲val my_list = myList(5) # 獲得一個生成器對象 print(my_list.__next__()) # 返回當前迭代值 print(my_list.__next__()) print(my_list.send(3)) # 從新設定當前的迭代值 print(my_list.__next__()) print dir(my_list)
打印結果:編程
三者簡要關係圖數據結構
可迭代對象與迭代器函數
剛開始我認爲這二者是等同的,但後來發現並非這樣;下面直接拋出結論:spa
1)可迭代對象包含迭代器。
2)若是一個對象擁有__iter__方法,其是可迭代對象;若是一個對象擁有next方法,其是迭代器。
3)定義可迭代對象,必須實現__iter__方法;定義迭代器,必須實現__iter__和next方法。.net
你也許會問,結論3與結論2是否是有一點矛盾?既然一個對象擁有了next方法就是迭代器,那爲何迭代器必須同時實現兩方法呢?命令行
由於結論1,迭代器也是可迭代對象,所以迭代器必須也實現__iter__方法。3d
介紹一下上面涉及到的兩個方法:code
1)__iter__()對象
該方法返回的是當前對象的迭代器類的實例。由於可迭代對象與迭代器都要實現這個方法,所以有如下兩種寫法。
寫法一:用於可迭代對象類的寫法,返回該可迭代對象的迭代器類的實例。
寫法二:用於迭代器類的寫法,直接返回self(即本身自己),表示自身便是本身的迭代器。
也許有點暈,不要緊,下面會給出兩寫法的例子,咱們結合具體例子看。
2)next()
返回迭代的每一步,實現該方法時注意要最後超出邊界要拋出StopIteration異常。
下面舉個可迭代對象與迭代器的例子:
#!/usr/bin/env python
# coding=utf-8
class 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-8
def 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,不然從新設定當前迭代值爲val
my_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迭代器和生成器
---------------------
做者:jinixin
來源:CSDN
原文:https://blog.csdn.net/jinixin/article/details/72232604
版權聲明:本文爲博主原創文章,轉載請附上博文連接!
def 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,不然從新設定當前迭代值爲val my_list = myList(5) # 獲得一個生成器對象 print my_list.next() # 返回當前迭代值 print my_list.next() my_list.send(3) # 從新設定當前的迭代值 print my_list.next() print dir(my_list)
打印結果:
<class '__main__.mylist'>
6
7
8
class mylist(object): def __init__(self,num): self.num = num self.list = [num+1,num+2,num+3] def __iter__(self): return mylistiterator(self.list) class mylistiterator(object): def __init__(self,data): self.data = data self.now = 0 def __iter__(self): return self def __next__(self): while self.now<len(self.data): self.now += 1 return self.data[self.now-1] raise StopIteration my_list = mylist(5) print(type(my_list)) for i in my_list: print(i)