一、說明
python中最早看到yield應該是使用scrapy框架寫爬蟲的時候,之前也有去看yiled的用法,總記不太住。今天又去看了一下,基本上來就是講些斐波那契數列的煩的要死
二、return和yield的異同
共同點:return和yield都用來返回值;在一次性地返回所有值場景中return和yield的作用是一樣的。
不同點:如果要返回的數據是通過for等循環生成的迭代器類型數據(如列表、元組),return只能在循環外部一次性地返回,yeild則可以在循環內部逐個元素返回。下邊我們舉例說明這個不同點。
三、實例說明
3.1 return版本
示例代碼如下:
class TestYield: def gen_iterator(self): result_list = [] for j in range(3): print(f"gen_iterator-{j}") result_list.append(j) # return在循環的外部,待變量完全生成后一次性返回 return result_list def call_gen_iterator(self): # 執行下邊這句后result_list直接是完成的結果[0,1,2] result_list = self.gen_iterator() for i in result_list: print(f"call_gen_iterator-{i}") if __name__ == "__main__": obj = TestYield() obj.call_gen_iterator()
執行結果如下,可以看到一次性執行完下層函數,生成完整的迭代器類型返回值result_list,一次性返回給上層函數:
3.2 yield版本
示例代碼如下:
class TestYield: def gen_iterator(self): for j in range(3): print(f"do_something-{j}") # yield在for循環內部 yield j def call_gen_iterator(self): # yield並不是直接返回[0,1,2],執行下邊這句后result_list什么值都沒有 result_list = self.gen_iterator() # i每請求一個數據,才會觸發gen_iterator生成一個數據 for i in result_list: print(f"call_gen_iterator-{i}") if __name__ == "__main__": obj = TestYield() obj.call_gen_iterator()
執行結果如下,可以看到上下層函數是交替進行的,即上層函數請求迭代一個值下層函數才生成一個值並立即返回這個值:
3.3 yield的意義
從上邊兩個小節可以看到,雖然return和yield兩者執行的順序有區別,但整個要做的事情是一樣的,所以使用yield並不會比return快,甚至我們可以猜測由於yield總發生上下文切換在速度上還會慢一些,所以速度不是yield的意義。
他們的主要區別是yiled要迭代到哪個元素那個元素才即時地生成,而return要用一個中間變量result_list保存返回值,當result_list的長度很長且每個組成元素內容很大時將會耗費比較大的內存,此時yield相對return才有優勢。
yield 生成器相比 return一次返回所有結果的優勢:
(1)反應更迅速
(2)更節省空間
(3)使用更靈活