yield:
對於yield方法和generator的send同時使用時的執行順序一直搞不清,今天看到這篇
理解php中的generator
加上測試,終於搞清了。
總結一下上文中的結論:
幾個經典的例子幫助理解!
1.經典的例子熱身
function xrange($start, $end, $step = 1)}foreach (xrange(1, 1000000) as
$num
)
$range = xrange(1, 1000000);var_dump($range); //
object(generator)#1
var_dump($range instanceof iterator); //
bool(true)
2.鳥哥部落格中的例子
3.乙個讀取檔案的例子,同時使用了send函式
/*a.log的內容
*/aaaaa
bbbbb
ccccc
ddddd
function linegenerator($file)}$lines = linegenerator("a.log");
foreach ($lines as $line
)
/*輸出結果
*/string(4) "test"aaaaa
nullstring(4) "test"ccccc
null
之前對於這個輸出結果一直理解不了,現在總結一下怎麼分析:
1.外層迴圈的每一次都會呼叫一次內層函式中yield的一行,執行完一次yield便停止執行。
2.對於var_dump(yield $line) 這樣的寫法,在分析時可以拆分為$var = (yield $line);var_dump($var);便於理解。
3.send()函式在呼叫時如果yield函式一次也沒被執行過,則會先執行一次yield(其實是在建立迭代器時已經隱式的執行了rewind方法),再進行賦值,再執行next(send有乙個next的功能)。
根據上邊的方法分析一下上邊的例子:
1.首先,根據總結的方法2先對linegenerator函式進行修改,因為a.log就4行,索性可以不用迴圈了。修改後如下:
function linegenerator($file)
2.foreach開始時,($lines as $line)肯定是呼叫了current()方法賦值$line,就是記憶體迴圈要執行一次yield,此時內層**執行到第二行,$line被賦值aaaaa。
3.接著,外層迴圈呼叫了$lines->send('test'),這時的test值會賦值給內層函式當前的yield(就是第乙個yield),然後執行第乙個var_dump(),列印出了test,然後執行第二個yield,並把yield的值賦給send函式的返回值(就是bbbbb),內層**停止。
5.foreach 進入下次迴圈,就是需要從函式上次停下的位置執行到下乙個yield執行完,函式先執行第二個var_dump(),此時當前的yield是null,所 以列印出null,接著執行第三個yield,獲取到a.log的第三行賦值給$line,即ccccc,函式執行停止。
6.然後迴圈執行$lines->send('test'),函式的第三個var_dump()就列印出test,執行第4個yield,把a.log的ddddd賦給send的返回值。函式執行停止。
8.foreach進入下一次迴圈,函式又要從上次停止的位置執行到下乙個yield結束,就是函式中最後乙個var_dump()執行,列印出null,因為後邊沒有yield了,**執行結束。
4.乙個日誌寫入的例子,可以說明呼叫send時沒有呼叫過yield的情況,用總結的第三個方法解決。
function logger($filename)}$logger = logger('a.log');
var_dump($logger->send('foo'));
var_dump($logger->send('bar'));
/*輸出結果
*/aaa
bbbaaa
null
bbbaaa
null
分析:
此時只是生成了乙個generator物件,yield並沒有執行。
2.外部第二行$logger->send('foo'),由於函式內部沒有yield,所以會先執行一次yield後再執行賦值,next()操作。執行一次yield,會列印出aaa,注意yield執行完但是fwrite並沒有執行,(這個可以算是send函式的初始化操作,哈哈)
接著才是像正常情況下的send執行一樣,進行next()操作,先把foo賦值給當前的yield,執行fwrite寫入,然後列印bbb,再列印aaa,執行
3.外部第三行執行$logger->send('foo'),此時內部函式整執行到fwrite,send把foo賦值給當前的yield,然後fwrite寫入,然後列印bbb,再列印aaa,執行到fwrite($filehandle,yield . "\n")停止執行。fwrite不執行,yield的返回值null,所以外部第二個var_dump()列印null。
附:yield輸出key,value:
$lineparts = explode(' ', $line, 2);yield
$lineparts[0] => $lineparts[1];
python生成器中yield和send分析
在python中生成器是指用 實現迭代器的的功能本質還是迭代器,只不過是 實現迭代器功能。在python中生成器是由函式實現的,通常我們在函式中加入yeild就可以實現生成器。定義乙個函式 def func print 111 yield 3 print 222 g func 執行上面 你會發現函式...
yield生成器中的send方法
yield生成器中提供了send方法,可以給生成器傳遞引數。我們可以使用以下函式感受 def foo print enter foo while true result yield 4 if result print send me a value d result,return else prin...
含yield的函式的執行過程
最近在了解python中的生成器,今天主要目的是闡述單執行緒實現並行效果,程式的執行過程。例子是廚師李老頭做一道菜,張 三 李四 王五三個臭小子就吃一道菜,使程式不斷穿梭在做菜,吃菜兩個程式中。一 import time def consumer name print s喊你來吃炒菜了 name w...