盤點那些不為人知的yield語法
2024-06-12 加入收藏
今天給大家?guī)肀容^硬核的知識點,yield
的使用高階版。
yield用于生成器產(chǎn)生單個值
大多數(shù)小伙伴肯定是從生成器函數(shù)中第一次看到的yield關鍵字的吧?
沒錯,這是yield
最常用的場景。
def simple_gen():
yield 1
yield 2
yield 3
gen = simple_gen()
print(next(gen)) # 輸出 1
print(next(gen)) # 輸出 2
上面的代碼,yield
用于在生成器函數(shù)中產(chǎn)生單個值。
控制權返回給調用者,但保留生成器的狀態(tài),使得下次調用next()
時可以從上一次yield
的位置繼續(xù)執(zhí)行。
如果將生成器放入循環(huán)語句中yield
可多次產(chǎn)生值
def simple_gen():
yield 1
yield 2
yield 3
gen = simple_gen()
for i in gen:
print(i)
# 輸出 1 2 3
yield from + 委托生成器
如果我有多個生成需要組合成一個生成器,并希望有順序地輸出值該怎么辦?
def generator1():
yield 1
yield 2
def generator2():
yield 3
yield 4
我可以這樣寫去實現(xiàn):
def generator1():
yield 1
yield 2
def generator2():
yield 3
yield 4
def combined_generator():
for i in generator1():
yield i
for i in generator2():
yield i
main_gen = combined_generator()
for i in main_gen:
print(i)
# 輸出 1 2 3 4
需要for循環(huán)才能實現(xiàn),有點難看...
引入yield from + 委托生成器之后進行改寫:
yield from
是python3.3版本引入的。
def generator1():
yield 1
yield 2
def generator2():
yield 3
yield 4
####################
def combined_generator():
yield from generator1()
yield from generator2()
####################
main_gen = combined_generator()
for i in main_gen:
print(i)
# 輸出 1 2 3 4
改寫后的代碼,yield from
用于在生成器函數(shù)(combined_generator)中委托部分生成任務給其他生成器(generator1,generator2), 而將子生成器的輸出直接傳遞給調用者,而不需要在主生成器中顯式循環(huán)子生成器的輸出。
更重要的是?。p少了循環(huán)的使用,減少了嵌套層次使得代碼更加簡潔。前提是你已經(jīng)學會了這個語法。
有yield參與的賦值語句
先上代碼:
def generator_function():
value = yield "hello"
print(f"從yield接收的值是{value}")
yield value
有沒有感覺到一臉懵???為什么yield能用于賦值語句???
說好的yield
和return
類似能在函數(shù)中返回一個值,怎么還能用于賦值語句???

我來強調下一件事:return
是返回后退出函數(shù),函數(shù)是被銷毀的。而yield
返回后是將函數(shù)掛起,函數(shù)還是存活的。
所以value = yield "hello"
這句執(zhí)行后,函數(shù)是被掛起的。
那從yield
那里接收的值是"hello"嗎?
不是的,從yield
中接收的值要從函數(shù)外部給它發(fā)送進去。
完整代碼:
def generator_function():
value = yield "hello"
print(f"從yield接收的值是{value}")
yield value
g = generator_function()
first = next(g)
print(first)
second = g.send("world") # 向yield發(fā)送要接收的值
print(second)
當send函數(shù)執(zhí)行后,會默認對生成器執(zhí)行next方法到下一個返回/掛起點。
代碼執(zhí)行結果:
hello
從yield接收的值是world
world
yield實現(xiàn)一個狀態(tài)機
如果對上面的知識點能略懂略懂,那么就可以看下這段狀態(tài)機的代碼鞏固下知識點。
def vending_machine():
state = "idle"
while True:
if state == "idle":
print("售貨機空閑。插入硬幣以開始售貨。")
coin = yield
if coin:
print("插入硬幣。切換到售貨狀態(tài)。")
state = "售貨中"
else:
print("未插入硬幣。保持在空閑狀態(tài)。")
elif state == "售貨中":
print("售貨機售貨中。按下按鈕以選擇商品。")
selection = yield
if selection:
print(f"售貨商品 {selection}。返回到空閑狀態(tài)。")
state = "空閑"
else:
print("未選擇商品。繼續(xù)售貨。")
# 創(chuàng)建狀態(tài)機生成器對象
vm_gen = vending_machine()
# 啟動狀態(tài)機
next(vm_gen)
# 模擬用戶操作
vm_gen.send(True) # 插入硬幣,切換到售貨狀態(tài)
vm_gen.send("蘋果汁") # 選擇商品,返回到空閑狀態(tài)
GPT對代碼解釋:
vending_machine 函數(shù)定義了一個狀態(tài)機,有兩個狀態(tài):"idle"(空閑)和 "vending"(售貨中)。 通過 while True 實現(xiàn)一個無限循環(huán),保持狀態(tài)機的運行。 在 "idle" 狀態(tài)下,狀態(tài)機等待硬幣的插入。如果收到硬幣,狀態(tài)切換到 "vending"。 在 "vending" 狀態(tài)下,狀態(tài)機等待用戶按下按鈕選擇商品。如果選擇了商品,狀態(tài)切換回 "idle"。 通過 yield 實現(xiàn)暫停和恢復狀態(tài)機的執(zhí)行。yield 語句在產(chǎn)生值的同時也接收到來自外部的輸入。 在主程序中,我們創(chuàng)建了狀態(tài)機生成器對象 vm_gen,并通過調用 next(vm_gen) 啟動了狀態(tài)機。然后,通過 vm_gen.send(True) 模擬了插入硬7. 幣的操作,再通過 vm_gen.send("蘋果汁") 模擬了選擇商品的操作。
如果還是對這段代碼存疑,最好再使用編輯器的debug跑一下一段代碼,觀察yield的狀態(tài)(作用)。