Python 生成器的next和send
阿新 • • 發佈:2018-12-09
1.什麼是生成器? 在 Python 中,使用了 yield 的函式被稱為生成器(generator)。 跟普通函式不同的是,生成器是一個返回迭代器的函式,只能用於迭代操作,更簡單點理解生成器就是一個可以迭代的東西。
2.next()與send() next()方法: 在呼叫生成器執行的過程中,每次遇到 yield ,函式返回當前的值,並且會暫停並儲存當前所有的執行資訊, 並在下一次執行 next() 方法時從當前位置繼續執行。
例項:
def _generator():
r = "Here"
for i in range(3):
yield r
r = '200 OK' + str(i)
g = _generator() # 生成器物件
first_next = g.__next__() # 第一次next
second_next = g.__next__() # 第二次next
third_next = g.__next__() # 第三次next
print(first_next)
print(second_next)
print(third_next)
執行結果:
Here
200 OK0
200 OK1
程式碼解讀:
首先,定義的 g=_generator() 並不是函式呼叫,而是產生生成器物件。
第一次,我們呼叫next ()方法,即:first_next = g.__next__(),
此時我們進入生成器函式_generator(),遇到yield返回,此時,r="Here",
所以,可以看到結果第一行為:"Here"。
第二次,我們同樣呼叫了next()方法,即:second_next = g.__next__(),
此時我們也是進入生成器,但是並不是從頭開始進入執行,而是從上一次的yield後面開始,
即:執行 r = '200 OK' + str(i),此時 r = '200 OK0',遇到yield返回,
所以,可以看到結果第一行為:"200 OK0"。
第三次,我們依舊呼叫了next()方法,即:third_next = g.__next__ (),
此時我們也是進入生成器,但是並不是從頭開始進入執行,而是從上一次的yield後面開始,
即:執行 r = '200 OK' + str(i),此時 r = '200 OK1',遇到yield返回,
所以,可以看到結果第一行為:"200 OK1"。
如果我們再加多有一次呼叫,forth_next = g.__next__() # 第四次next,
就會報錯:
Traceback (most recent call last):
File "C:/Users/10475/Desktop/Spider_Project/Scrapy_Project/tools/multiprocessing_demo.py", line 76, in <module>
forth_next = g.__next__() # 第四次next
StopIteration
原因是:
執行3次yield後,此時,i已經為2了,頂天了,已經沒有yield可以執行了,
所以,第4次呼叫next(o)就報錯。
在平時使用生成器,我們更多的去使用for迴圈去迭代生成器,上面也提到,
generator是一個可以迭代的物件,所以結果也是一樣的。
例項改寫:
def _generator():
r = "Here"
for i in range(3):
yield r
r = '200 OK' + str(i)
g = _generator() # 生成器物件
for i in g:
print(i)
send()方法: 先理解個概念【掛起】:意思就是暫時保留先不進行,等待需要時再進行。 作用:與next()作用相似 區別: 1.send(value)可以傳遞value給yield,即:我們可以指定yield返回啥就返回啥, 2.next()不能傳遞特定的值,只能傳遞None進去。
第一次呼叫時,請使用next()語句或是send(None),不能使用send傳送一個非None的值,否則會出錯的,可以看到,can't send non-None value to a just-started generator
因為生成器just-started generator
,是沒有Python yield語句來接收這個值的。
Traceback (most recent call last):
File "C:/Users/10475/Desktop/Spider_Project/Scrapy_Project/tools/multiprocessing_demo.py", line 87, in <module>
g.send(1)
TypeError: can't send non-None value to a just-started generator
例項1:
def _generator():
for i in range(4):
n = yield i
if n == 'hello':
print('world')
else:
print(str(n))
g = _generator() # 生成器物件
print(g.__next__()) # 結果是:0
print(g.__next__()) # 結果是:None
執行結果:
0
None
1
程式碼解讀:
第一次呼叫g.__next__(),跑到 yield i,遇到yield,返回結果為0。
第二次呼叫g.__next__(),繼續從上一次狀態繼續執行,此時,需要注意,
我們執行的起點是:n = yield i,並且這個n值並不是i值,而是通過send()傳遞過來的值,
即:n = send(),但是我們沒有呼叫send()方法,所以,n自然而然為None,
所以,此時是執行print(g.__next__()),結果為None。
緊接著,我們還在繼續,yield完以後,n就有值了,此時為None,
我們進入判斷語句,此時是執行print(str(n)),結果為1。
例項2:
def _generator():
for i in range(4):
n = yield i
if n == 'hello':
print('world')
else:
print(str(n))
g = _generator() # 生成器物件
# print(g.__next__())
print(g.send(None)) # 相當於g.__next()__
程式碼解讀:
呼叫send()方法,傳入value為None,此時相當於next()方法,效果自然與next()一樣,
即:遇到yield就返回,返回結果為:0,所以print(0)。
例項3:
def _generator():
for i in range(4):
n = yield i
if n == 'hello':
print('world')
else:
print(str(n))
g = _generator() # 生成器物件
g.send(None) # 相當於g.__next__()
g.send('100')
g.send('Python')
g.send('hello')
執行結果:
100
Python
world
程式碼解讀:
g.send(None):
相當於g.__next__()作用,遇到yield返回,返回一個0,由於沒有誰列印0,自然看不到。
g.send('100'):
繼續從上一次狀態出發,起點為:n ,(再次提醒:n 不等於 yield i)此時n = send(100),
即:n = 100,進入判斷,print(str(n)),結果也就是我們看到的第一行100。
g.send('Python'):
繼續上一次狀態出發,起點為:for i in range(4),
此時n = send('Python'),即:n = 'Python',進入判斷,print(str(n)),
結果也就是我們看到的第二行"Python"。
g.send('hello'):
繼續上一次狀態出發,起點為:for i in range(4),
此時 n = send('hello'),即:n = 'hello',進入判斷,print('world'),
結果也就是我們看到的第三行"world"。
如果我們再加多一行:g.send('Scrapy'),結果為:
Traceback (most recent call last):
100
File "C:/Users/10475/Desktop/Spider_Project/Scrapy_Project/tools/multiprocessing_demo.py", line 91, in <module>
Python
world
Scrapy
g.send('Scrapy')
StopIteration
為什麼會報錯?
因為超出了range(4),前面已經實現了4次,(send(None)也要算上),
這一次加了g.send('Scrapy')是第五次,所以報錯。
為什麼還會有輸出?
我的理解是:雖然報錯,但是,我壓根都不需要你這個i,我的n = send('Scrapy'),
即:n = "Scrapy",依舊進入迴圈,依舊print(str(n)),所以有輸出。