php中Generator(生成器)的執行過程

2020-12-14 I024

說到php中的Generator(生成器),有人可能會想到協程,這裡我們先不說php如何實現協程,我們探究下Generator的執行過程。

Generator是通過yield實現,yield 關鍵字是php5.5版本推出的一個特性。 首先,看下面的代碼:

<?php

function gen(){

while(true){

yield "gen\n";

}

}

$gen = gen();

echo "Generator";

如果沒有了解過yield的話,你會認為上面代碼執行的結果是:死循環。但實際上,它會echo出Generator。

到這裡,也許你會覺得奇怪,yield怎麼可以結束循環?下面就為大家說明一下:

Generator提供的方法:

Generator::current — 返回當前產生的值

Generator::key — 返回當前產生的鍵

Generator::next — 生成器繼續執行

Generator::rewind — 重置迭代器

Generator::send — 向生成器中傳入一個值

Generator::throw — 向生成器中拋入一個異常

Generator::valid — 檢查迭代器是否被關閉

Generator::__wakeup — 序列化回調

生成器提供了一種更容易的方法來實現簡單的對象迭代(迭代器),相比較定義類實現 Iterator 接口的方式,性能開銷和複雜性大大降低。

大家看下這個列子:

function gen(){

for($i=0;$i<5;$i++){

echo (yield $i).$i.'<br/>';

}

}

$gen = gen();

foreach($gen as $k=>$v){

echo "{$k}---{$v}".'<br/>';

}

結果:

結果

從上面的結果,我們可以分析出以下幾點:1當Generator對象被foreach的時候,內部的valid,current,key方法會依次被調用,其返回值是foreach語句的value和key。2循環的終止條件則根據valid方法的返回而定。如果返回的是true則繼續循環,如果是false則終止整個循環,結束遍歷。3一次循環體結束之後,將調用next進行下一次的循環直到valid返回false。而rewind方法則是在整個循環開始前被調用(也就是生成Generator對象時),這樣保證了我們多次遍歷得到的結果都是一致的。

下面我們來證明一下這個流程:

$gen = gen();echo $gen->key();//結果是0,生成Generator對象時,rewind已經執行。echo $gen->key().'----'.$gen->current();// 0----0 var_dump($gen->next());//var_dump值是null,但是還會echo出多一個0;這個0是怎樣來的呢?原因是:next()執行後,第1個yield到第二個yieldz之間的的語法被執行,即是:echo (yield $i).$i.'<br/>';由於next()是沒有返回值,即(yield $i)這個表達式沒有值,而$i的值是0;echo $gen->key().'----'.$gen->current();// 1----1 目前是第2個yield

上面這個例子可以證明,Generator內部的流程,特別注意next()的理解。

最後,我們說一下,send():

官方解析:向生成器中傳入一個值,並且當做 yield 表達式的結果,然後繼續執行生成器。如果當這個方法被調用時,生成器不在 yield 表達式,那麼在傳入值之前,它會先運行到第一個 yield 表達式。

翻譯下的結論是:send()方法主要用於發送數據給當前yield,即yield表達式被當作一個值被替換,且繼續執行下一個yield,即next()

證明例子:$gen = gen();$gen->send(666);//6660

6660結果分析:首先把666代替當前yield表達式的值,然後執行next(),即運行echo (yield $i).$i.'<br/>',當前yield是666,所以最終結果是:6660。注意與next()的區別!!!

總結:1.yield只能用於函數內部,在非函數內部運用會拋出錯誤。2.如果函數包含了yield關鍵字的,那麼函數執行後的返回值永遠都是一個Generator對象。3.如果函數內部同事包含yield和return 該函數的返回值依然是Generator對象,但是在生成Generator對象時,return語句後的代碼被忽略。4.Generator類實現了Iterator接口。5.可以通過返回的Generator對象內部的方法,獲取到函數內部yield後面表達式的值。6.可以通過Generator的send方法給yield 關鍵字賦一個值。7.一旦返回的Generator對象被遍歷完成,便不能調用他的rewind方法來重置。8.Generator對象不能被clone關鍵字克隆 。

實際應用:1.協程2.Genenrator返回的是迭代器,在處理大數據的時候不用一次性的加載到內存中。

相關焦點

  • php性能優化利器Generator生成器及yield
    php生成器的核心是一個yield關鍵字,一個生成器函數看起來像一個普通的函數,不同的是:普通函數返回一個值,而一個生成器可以yield生成許多它所需要的值。生成器函數被調用時,返回的是一個可以被遍歷的對象。
  • Python數據讀取之生成器(generator)
    Python生成器是創建迭代器的簡單方法。簡單來說,生成器是一個函數,它返回一個我們可以迭代的對象(迭代器),迭代器一次返回一個值較使用列表將所有數據都加載到內存中,生成器節省了大量內存空間。深度學習的數據讀取部分一般都需要使用迭代器。
  • python之generator生成器模擬資料庫主鍵自增
    在python中,生成器就可以做到這一點。生成器語法格式1、同列表生成式一樣,唯一區別是將「[]」換成「()」。2、生成器函數(函數內部使用yield)說明:如果在函數中出現了yield關鍵字,則這個函數不再是普通的函數,而是一個生成器,其實這個yield的含義就是將一個普通函數變成一個生成器。這種方式下,生成器可以實現無限制的列表元素,而列表生成式就無法做到這一點。
  • Python小白教程:生成器 (generator) 和迭代器 (iterator)
    如何來看生成器裡的元素呢?有兩種方法:1. 轉換成 list;2. 用 next()。雖然列印出了結果,但這不是生成器的用法。這樣做的話還不如直接用列表解析式呢。生成器中真正有特點的用法是用 next() 把不斷獲得下一個返回值。先列印出一個元素。
  • python中的yield和return—迭代器和生成器
    yield和return之前一篇文章【開啟Scrapy爬蟲之路】中,處理item時,定義函數返回值用的yield,有人問yield是幹嘛的,什麼意思?相同點:都是定義函數過程中返回值不同點:yield是暫停函數,return是結束函數;即yield返回值後繼續執行函數體內代碼,return返回值後不再執行函數體內代碼yield返回的是一個迭代器(yield本身是生成器-生成器是用來生成迭代器的);return返回的是正常可迭代對象(list,set,dict等具有實際內存地址的存儲對象)
  • 快速了解 ES6 的生成器
    function* generator() {}注意:箭頭函數不能用來定義生成器函數。方法調用生成器函數會產生一個符合可迭代協議和迭代器協議的生成器對象。生成器對象一開始處於暫停執行的狀態。與迭代器相似,生成器也實現了 Iterator 接口。
  • 提高 Python:解釋 yield 和 生成器
    協程與子例程我們調用一個普通的Python函數時,一般是從函數的第一行代碼開始執行,結束於return語句、異常或者函數結束(可以看作隱式的返回None)。一旦函數將控制權交還給調用者,就意味著全部結束。函數中做的所有工作以及保存在局部變量中的數據都將丟失。再次調用這個函數時,一切都將從頭創建。對於在計算機編程中所討論的函數,這是很標準的流程。
  • 工具推薦:15款代碼生成器
    15款代碼生成器, 從弱智的色彩漸變代碼生成器, 到CSS生成器, 再到適合開發人員的.NET代碼生成器.Cssronnd – 在線生成css圓角代碼,可以設置圓角半徑、包含文字、圓角顏色、背景顏色、文字顏色以及寬度。支持代碼下載(其中包括4個圓角圖片)。
  • 一文搞懂Python迭代器和生成器
    這篇文章就是要用最簡單的方式讓你理解Python迭代器和生成器!在Python中,迭代器是遵循迭代協議的對象。使用iter()從任何序列對象中得到迭代器(如list, tuple, dictionary, set等)。另一種形式的輸入迭代器是generator(生成器)。
  • 從零開始學Python-Day22-生成器
    生成器上一節列表生成式可以用來生成一個完整list,但是如果需要的list容量很大呢?如果需要一個100萬個元素的列表,難道要生成這樣一個list麼,那不是很佔內存麼?更何況我們可能並不需要這個列表中的所有元素。
  • 雲計算開發學習筆記:Python3迭代器與生成器
    創建一個迭代器把一個類作為一個迭代器使用需要在類中實現兩個方法 __iter__() 與 __next__() 。創建一個返回數字的迭代器,初始值為 1,逐步遞增 1:執行輸出結果為:StopIterationStopIteration 異常用於標識迭代的完成,防止出現無限循環的情況,在 __next__() 方法中我們可以設置在完成指定循環次數後觸發
  • Python生成器next方法和send方法區別詳解
    住址"python 生成器和迭代器的原理解析一.生成器簡介 在python中,生成器是根據某種算法邊循環邊計算的一種機制.主要就是用於操作大量數據的時候,一般我們會將操作的數據讀入內存中處理,可以計算機的內存是比較寶貴的資源,我認為的當要處理的數據超過內存四分之一的大小時就應該使用生成器. 二.生成器有什麼特點?
  • 什麼是Python的迭代器和生成器?(附代碼)
    在處理大量數據時,計算機內存可能不足,我們可以通過生成器和迭代器來解決該問題。迭代器:一次一個!Python 是一種美麗的程式語言。我喜歡它提供的靈活性和難以置信的功能。我喜歡深入研究Python的各種細微差別,並了解它如何應對不同的情況。在使用Python的過程中,我了解到了一些功能,這些功能的使用與其簡化的複雜度不相稱。
  • PHP高級之一次請求處理過程或生命周期詳解
    以上過程只是個簡略版,讓我們再深入挖掘一下,看看幕後還發生了些什麼。同時,它還建立一個變量表,用來存放執行過程中產生的變量名和值。PHP調用各個模塊的RINIT方法,即「請求初始化」。一個經典的例子是Session模塊的RINIT,如果在php.ini中啟用了Session模塊,那在調用該模塊的RINIT時就會初始化$_SESSION變量,並將相關內容讀入;RINIT方法可以看作是一個準備過程,在程序執行之間就會自動啟動。
  • Python 生成器之細說 yield
    )中我們留了這麼一個問題:「yield 除了作為生成器的標誌以外,還有一個「返回值」的功能,我們知道 return 也有這個功能,那麼它跟 return 的這個返回值有什麼區別呢」?>>> s = self_return(3)rockybefore return>>> s3從上面的例子中函數 self_return(n) 被調用的過程中我們可以清晰的看出
  • 傳智播客鄭州校區Python學習之迭代器與生成器
    在Python中,一邊循環一邊計算的機制,稱為生成器(generator)。生成器可以理解為一種數據類型,這種數據類型自動實現的迭代器協議(其他的數據類型是通過調用自己的內置方法_iter_方法),所以生成器就是可迭代對象,直接就可以使用_next_()方法。  生成器分類在python中的表現形式(python有兩種不同的方式提供生成器)  1.生成器表達式,生成器其實就是把列表生成器的[]變為()。
  • Python生成器的使用
    對,沒錯,它不是元組,這是一個生成器對象。生成器對象是一類特殊的迭代器對象,它遵循迭代器(iterator)協議(迭代器協議需要實現__iter__、__next__接口,案例參見有了它,出門旅遊再也不怕感冒了,Python使用迭代器進行天氣預報)。最重要的是,它可以實現使用時取出,不用時不佔用內存的作用。
  • 標題黨文章生成器
    前段時間「狗屁不通文章生成器」廣受好評。受該項目的啟發,我編寫了標題黨文章生成器。因此,在得知有在線版的狗屁不通文章生成器的時候,我還納悶這個在線版文章生成器得需要多少塊GPU才能實現大量用戶同時使用。結果事實上,該文章生成器一點AI的算法也沒有用!「狗屁不通文章生成器」通過採用不斷隨機重複已有語料庫中的句子,並時不時插入關鍵詞從而達到狗屁不通卻又緊貼文章主題的效果。
  • ​如何使用生成器減少內存佔用,並讓Python代碼運行更快?
    本文轉載自公眾號「讀芯術」(ID:AI_Discovery)如何使用生成器減少內存佔用並讓Python代碼運行更快,關乎你「代碼人生」的生死存亡。 然而,當我剛開始學習Python生成器時,並不知道它最後會顯得如此重要。 但在學習機器學習的過程中需要編寫自定義函數時,它發揮了不可取代的作用。