做者:清菡
博客:oschina、雲+社區、知乎等各大平臺都有。微信
因爲微信公衆號推送改成了信息流的形式,防止走丟,請給加個星標 ⭐,你就能夠第一時間接收到本公衆號的推送!
1、迭代器函數
2、生成器性能
一種是包含iter
方法的,另外一種是包含getitem
方法的(好比str
對象就沒有iter
方法,可是同樣可以迭代),只要對象中包含了這兩種方法的任意一種,那麼這個對象就能夠進行迭代操做,也就是實現了迭代協議。測試
生成器是迭代器的一種。迭代器的範圍比生成器更廣。只要能夠經過next()
,從裏面一個一個往外面取值,都被稱爲迭代器。編碼
關於要建立一個迭代器對象,那麼內部要實現一個迭代器的協議。spa
iter()
方法)。__next__
方法。__next__
方法返回了某個數值(固然通常狀況下,咱們須要的是返回這個對象的特定的數字,而且按照必定的順序進行依次返回)。__next__
方法須要在值取完的時候,拋出stopiteration
的錯誤信息。有個東西須要區分,一個是迭代器,一個是可迭代對象。code
只要內部實現了迭代協議的就是一個可迭代對象(可迭代對象能夠進行相關的迭代操做,好比for
循環,map
函數等)。對象
能夠用 for 循環進行遍歷的,那麼都是可迭代對象。可迭代對象不必定是迭代器,迭代器是在可迭代基礎上,它內部要首先定義一個__next_
方法。blog
迭代器內部實現了一個__next_
方法,實現了這個方法以後,經過__next_
這個函數才能夠對這個迭代器進行一個取值。rem
還有個iter()
方法,這個方法可將可迭代對象轉換成一個迭代器。
yield
和return
是 2 個東西。yield
只是暫停那個生成器函數。yield
能夠從生成器裏面生成一個內容。
列表能夠進行 for 循環,能夠進行 for 循環遍歷,它就是個可迭代對象。 列表是能夠經過 for 循環遍歷的,可是它不是迭代器。
迭代器是能夠經過next()
進行取值的。
生成器也是迭代器,生成器是能夠經過next()
去取值。那麼,生成器它是迭代器的一種,是屬於迭代器的。
你看,報錯了:
# 列表 # 可迭代對象:能夠for循環遍歷的都是可迭代對象 li = [1,2,3,4] next(li) print(next(li))
提示:列表它不是一個迭代器。
不是個迭代器,不能經過這個去取值。要把一個可迭代對象轉換成一個迭代器的話,經過iter()
這個函數把可迭代對象放進去,它可以返回一個迭代器。
你看,這樣就能獲取到了:
# 列表 # 可迭代對象:能夠for循環遍歷的都是可迭代對象 li = [1,2,3,4] li1 = iter(li) print(next(li1)) print(next(li1))
經過iter()
這個函數,來處理某個對象,它實際上至關於觸發這個對象內部的一個__iter__
這個方法。
我們看看list()
的源碼:
經過iter()
這個函數把對象li
傳進去的時候,它會觸發li
這個對象對應的__iter_
這個方法。
若是經過next()
去取值,把li1
這個對象傳進去的時候,其實是觸發這個對象的__next__
方法。
它的類裏面只有這個__iter__
方法。
迭代器能夠經過__next__
取值。迭代器內部實現了__next__
方法。
迭代器內部實現了 __iter__
方法以外,還實現了__next__
方法。
生成器是迭代器的一種。
迭代器是在可迭代對象的基礎上實現了__iter_
方法。迭代器和生成器均可以支持迭代操做。
for 循環。
生成器是迭代器的一種。 剛纔用起來的時候好像沒有什麼區別,打印下這個類型看看。
能夠看到,它返回的是個列表迭代器對象:
這個是生成器對象:
li1 = iter(li)
這個是可迭代對象。而後經過iter()
轉換成一個迭代器。
send()方法 | 發送數據 |
---|---|
close() 方法 | 關閉生成器 |
throw() 方法 | 使用的 throw 指令拋出錯誤 |
生成器是有send
這個方法的,迭代器是沒有的。
例如,前面有個生成器叫作tu
:
# () 生成器表達式 tu = (i for i in range(1000))#生成器對象 print(tu)
tu
能夠調用send()
這個方法,能夠與生成器進行交互,可將數據傳輸到生成器裏面。
舉個栗子:
生成器是迭代器的一種。
例如定義了一個父類,再有個子類,父類建立出一個對象,子類建立出一個對象。子類有本身的方法。父類建立的出來的對象裏面,確定沒有子類對象裏面的方法。 子類裏面有的方法,父類裏面沒有。
迭代器就是「父類」。生成器就是「子類」。
def gen(): for i in range(1,5): yield i gen()
生成器運行的時候,調用函數gen()
,調用這個函數的時候,這個函數裏面的代碼不會直接運行。
代碼修改爲這樣:
def gen(): for i in range(1,5): yield i g = gen() print(g)
只有經過next()
方法往生成器裏面取值的時候,它纔會從代碼上面往下面運行。
這個send()
方法可將數據傳到生成器裏面。使用next()
,從生成器裏面獲取出一個值。若是使用send()
方法,它也可以獲取出來一條數據。
def gen(): for i in range(1,5): se = yield i print(se) g = gen() print(next(g)) print(g.send(100))
send()
方法能夠往生成器裏面傳入一個值。
經過send()
方法生成數據的時候,它也能夠往裏面發送一個 100 的值。
若是經過next()
去取值的話,這個yield
完畢後是沒有返回內容的。
代碼詳解:
第一輪: 循環進來,經過next()
去取值生成了一個 1:
def gen(): for i in range(1,5): se = yield i print(se) g = gen() print(next(g))
第二輪: 經過print(g.send(100))
去發送值,而後打印:
def gen(): for i in range(1,5): se = yield i print('se的值:',se) g = gen() print(next(g)) print(g.send(100))
在第一輪結束以後,在yield
這裏,yield
完畢就中止了。在第一輪yield
完以後,第二輪經過send()
傳值進去,傳到se
那裏,打印出來 100。
而後再往上返回一個數據,又暫停,返回第二條數據就是個 2。
第三輪: 經過next()
再去生成一條元素,又觸發了yield i
這個地方,這裏釋放了,日後面走,日後面走的話,可是沒有放數據進來,這個時候se
是空的,打印出來的se
是空的。
而後再往上,生成一條元素到 3,而後又停在yield i
這個地方了,生成完元素,把這個值返回出去。
def gen(): for i in range(1,5): se = yield i print('se的值:',se) g = gen() print(next(g)) print(g.send(100)) print(next(g))
再次next()
或者send()
來觸發它的時候,它會這樣走:
注意: yield
接收不是存在i
中,這個yield
返回出來的i
是遍歷出來的內容。
send()
發進去的,是yield i
這裏運行完畢以後,當下一個send()
觸發的時候,它把這個值發送到yield i
這裏運行完畢以後的一個結果。
yield i
這裏把這個i
返回出去,就停在這裏不動了。send()
發送個數據進去,那麼數據就發送到個yield i
這地方。
至關於yield i
這個地方返回的一個結果,也就是send()
發進去的內容,若是send()
不發進去內容,返回出來是個空的。
舒適提示:生成器<迭代器<可迭代對象
公衆號 「清菡軟件測試」 首發,更多原創文章:清菡軟件測試 109+原創文章,歡迎關注、交流,禁止第三方擅自轉載。