Python生成器

生成器詳解

1.什麼是迭代器

只要定義了__iter__的類那麼他就是一個可迭代對象,若是定義了__next__方法那麼他就是一個迭代器.python

2.迭代器與生成器的區別

生成器是一種迭代器,可是迭代器不必定是生成器函數

3.什麼是生成器

簡單理解爲每次生出(yield)一個值的東西code

例子:協程

def generator():
    for i in range(3):
        yield i

這個函數就是一個生成器,與普通函數不一樣的是,當函數執行到yield i語句時,函數會被掛起而且把yield後面的i給返回,當你再次執行該函數時會從yield語句後面接着執行對象

不一樣於return語句的是,return語句不會掛起事件

4.生成器的優勢

因爲生成器每調用一次就只執行一次,因此生成器佔用獲得內存就會很是少,看個循環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

5.生成器的使用

能夠使用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

6.可迭代對象與迭代器

可迭代對象不必定是迭代器

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'

7.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

對輸出結果的解釋:

  1. 爲何第一次調用next沒有打印東西?

    由於代碼在yield語句處掛起,沒有執行到print語句

  2. 爲何有些地方獲得輸出是None

    Noneprint語句的輸出結果,輸出爲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

8.協程

協程是一種多任務(讓人感受同一時間發生了多種事件)的實現方式,生成器能夠實現協程

例:

#!/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被調用----

...
相關文章
相關標籤/搜索