很古老的用法了,現在大多用的aiohttp庫實現,這篇記錄僅僅用做個人的協程底層實現的學習。
爭取用看得懂的字來描述問題。
如果還沒有怎麼用過的話,直接把yield看做成一種特殊的return(PS:本質 generator(生成器))
return是返回一個值然後就終斷函數了,而yield返回的是一個生成器(PS:不知道的直接看作特殊列表,看下面的程式碼案例)
# -*- coding: utf-8 -*-
# @Time : 2022/11/10 16:17
# @Author : 紅後
# @Email : [email protected]
# @blog : https://www.cnblogs.com/Red-Sun
# @File : 範例1.py
# @Software: PyCharm
def main():
'''
遍歷0到4,這五個數,並分別列印
'''
for num in range(5):
yield num
if __name__ == '__main__':
for num in main():
print(num)
print('-'*50)
for num in [0, 1, 2, 3, 4]:
print(num)
將它看作列表用for迴圈遍歷,就能取出其中的值。
它與原來列表的區別就在於,自帶的列表是固定的,而把yield看作列表的話是動態的。
具體案例描述請看程式碼及備註(PS:個人自己描述的,有不對的地方望各位指點)
# -*- coding: utf-8 -*-
# @Time : 2022/11/14 13:24
# @Author : 紅後
# @Email : [email protected]
# @blog : https://www.cnblogs.com/Red-Sun
# @File : 範例2.py
# @Software: PyCharm
def main():
'''
將yield看作一個動態列表,從yield左往右為傳出資料,從又往左為傳入資料。
PS:有yield存在的那一行,需要從左往右傳出資料跑一遍,資料出去以後又要從又往左帶接收的資料跑一遍,一共一行跑兩邊(僅作者個人記憶方法)
'''
num1 = yield
num2 = yield
print(num1, num2)
yield num1 + num2
if __name__ == '__main__':
a = main()
# 第一個next對應第一個yield的右邊為空即None,所以動態列表中加入一個引數為None,返回值為列表的-1位是None
print(next(a)) # [None]
# 第二個通過send方法傳入一個數1,即在上一次停止的地方從右往左傳入引數,所以給num1賦值為1.然後繼續找下一個yield,其右邊的值依舊為None,加入動態列表,此時返回值-1位依舊是None
print(a.send(1)) # [None, None]
# 第三通過send方法傳入一個數2,即在上一次停止的地方從右往左傳入引數,所以給num2賦值為2.然後繼續找下一個yield,其右邊的值為num1 + num2,此時num1為1,num2為2,計算得返回值-1位為3
print(a.send(2)) # [None, None, num1 + num2]
yield from 後面需要加可迭代物件
當它後面加上生成器(上述所說的yield這種)便可以實現生成的巢狀
其中委派生成器的作用:在主程式與子生成器之間建立一個雙向通道。
所謂雙向通道是指,主程式可以將引數通過send傳遞給子生成器,子生成器的yield的值也可以直接返回給主函數。(PS:委派生成器只有建立通道的作用,沒有攔截資料這種功能)
也許有人會想直接用主程式呼叫子生成器不就行了,而對這的解釋是,使用yield from作為中間過渡是為了讓它幫我們進行例外處理(PS:類似寫程式為了正常執行加上try一個道理)
# -*- coding: utf-8 -*-
# @Time : 2022/11/10 15:13
# @Author : 紅後
# @Email : [email protected]
# @blog : https://www.cnblogs.com/Red-Sun
# @File : coroutines.py
# @Software: PyCharm
import requests
def coroutines_spider():
'''
子生成器(PS: 打工仔,真正幹活的)
'''
response = None # 首次啟用返回None,後期網頁響應覆蓋
while True:
url = yield response
response = requests.get(url)
def appoint():
'''
委派生成器,委託子生成器完成具體任務 (PS: 類似包工頭負責勞務派遣)
'''
while True:
yield from coroutines_spider() # 建立子生成器和主函數的雙連結
def main(url_list: list):
'''
主函數(PS: 相當於老闆,張貼招人啟示)
'''
ul = appoint() # 建立委派生成器
next(ul) # 啟用它
for url in url_list:
response = ul.send(url) # 將url作為引數傳遞進入子生成器中,返回子生成器yield出來的response
print(response.url, response.status_code) # 列印出response中的連結和狀態碼
if __name__ == '__main__':
url_list = ['https://www.baidu.com/', 'https://www.4399.com/', 'https://cn.bing.com/', ]
main(url_list=url_list)