yield和send的執行循序徹底搞清

2021-09-08 11:28:23 字數 2974 閱讀 3181

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