只要定義了__iter__
的類那麼他就是一個可迭代對象
,若是定義了__next__
方法那麼他就是一個迭代器.python
生成器
是一種迭代器
,可是迭代器
不必定是生成器函數
簡單理解爲每次生出(yield)一個值的東西code
例子:協程
def generator(): for i in range(3): yield i
這個函數就是一個生成器,與普通函數不一樣的是,當函數執行到yield i
語句時,函數會被掛起而且把yield
後面的i
給返回,當你再次執行該函數時會從yield
語句後面接着執行對象
不一樣於return
語句的是,return
語句不會掛起事件
因爲生成器每調用一次就只執行一次,因此生成器佔用獲得內存就會很是少,看個循環100000000次的例子ip
In [185]: def func(): ...: for i in range(100000000): ...: pass ...: In [186]: def gene(): ...: for i in range(100000000): ...: yield ...: In [187]: def getTime(f): ...: start = time.time() ...: f() ...: end = time.time() ...: print(end-start) ...: In [188]: getTime(func) 2.0609002113342285 In [189]: getTime(gene) 2.6226043701171875e-06
能夠使用next()
函數或者__next__()
方法來取值,當到最後一個值時會產生異常.內存
也可以使用for
語句取值,而且for
語句會自動處理這個異常.utf-8
next()
例子:get
In [146]: def generator(): ...: for i in range(3): ...: yield i ...: In [147]: g = generator() In [148]: next(g) Out[148]: 0 In [149]: next(g) Out[149]: 1 In [150]: next(g) Out[150]: 2 In [151]: next(g) --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-151-e734f8aca5ac> in <module> ----> 1 next(g) StopIteration:
__next__()
例子:
In [146]: def generator(): ...: for i in range(3): ...: yield i ...: In [147]: g = generator() In [148]: next(g) Out[148]: 0 In [149]: next(g) Out[149]: 1 In [150]: next(g) Out[150]: 2 In [151]: next(g) --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-151-e734f8aca5ac> in <module> ----> 1 next(g) StopIteration:
for
例子:
In [146]: def generator(): ...: for i in range(3): ...: yield i ...: In [147]: g = generator() In [148]: next(g) Out[148]: 0 In [149]: next(g) Out[149]: 1 In [150]: next(g) Out[150]: 2 In [151]: next(g) --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-151-e734f8aca5ac> in <module> ----> 1 next(g) StopIteration:
注意:不要這樣寫
In [162]: def generator(): ...: for i in range(3): ...: yield i ...: In [163]: next(generator()) Out[163]: 0 In [164]: next(generator()) Out[164]: 0 In [165]: next(generator()) Out[165]: 0
直接調用生成器,每次會從頭開始,這樣就永遠只能取到第一個值.(可是for
循環能夠使用)
In [162]: def generator(): ...: for i in range(3): ...: yield i ...: In [166]: for i in generator(): ...: print(i) ...: 0 1 2
可迭代對象不必定是迭代器
str
是可迭代對象,可是他不是迭代器:
In [191]: string = "abcdefg" In [192]: for i in string: ...: print(i) ...: a b c d e f g In [193]: next(string) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-193-50005732e4cf> in <module> ----> 1 next(string) TypeError: 'str' object is not an iterator
將可迭代對象轉換成迭代器:
In [194]: string = iter(string) In [195]: next(string) Out[195]: 'a' In [196]: next(string) Out[196]: 'b' In [197]: next(string) Out[197]: 'c'
send
函數使用send
函數能夠向生成器發送數據,yield
左邊的變量會接收:
In [205]: def generator(): ...: for i in range(10): ...: recv = yield i ...: print(recv) ...: In [206]: g = generator() In [207]: next(g) Out[207]: 0 In [208]: next(g) None Out[208]: 1 In [209]: g.send("hahaha") hahaha Out[209]: 2 In [210]: g.__next__() None Out[210]: 3 In [211]: g.__next__() None Out[211]: 4
對輸出結果的解釋:
爲何第一次調用next
沒有打印東西?
由於代碼在
yield
語句處掛起,沒有執行到
爲何有些地方獲得輸出是None
None
是None
是由於recv
變量沒有接收到數據
注意:
第一次執行就使用send
會報錯:
In [213]: def generator(): ...: for i in range(10): ...: recv = yield i ...: print(recv) ...: In [214]: g = generator() In [215]: g.send("hahahaha") --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-215-046ffd60433c> in <module> ----> 1 g.send("hahahaha") TypeError: can't send non-None value to a just-started generator
錯誤提示爲:不能將一個非None
的數據傳給剛開始的生成器.
那麼就能夠這麼寫
In [216]: g.send(None) Out[216]: 0
注意:什麼都不寫不表明None
協程是一種多任務(讓人感受同一時間發生了多種事件)的實現方式,生成器能夠實現協程
例:
#!/usr/bin/python3 # -*- coding: utf-8 -*- def func1(): while True: yield print("----func1被調用----") def func2(): while True: yield print("----func2被調用----") def main(): f1 = func1() f2 = func2() while True: next(f1) next(f2) if __name__ == '__main__': main()
output:
----func1被調用---- ----func2被調用---- ----func1被調用---- ----func2被調用---- ----func1被調用---- ----func2被調用---- ----func1被調用---- ----func2被調用---- ----func1被調用---- ----func2被調用---- ----func1被調用---- ...