盤點那些不為人知的yield語法
2024-06-12 加入收藏
今天給大家帶來比較硬核的知識點,yield
的使用高階版。
yield用于生成器產生單個值
大多數小伙伴肯定是從生成器函數中第一次看到的yield關鍵字的吧?
沒錯,這是yield
最常用的場景。
def simple_gen():
yield 1
yield 2
yield 3
gen = simple_gen()
print(next(gen)) # 輸出 1
print(next(gen)) # 輸出 2
上面的代碼,yield
用于在生成器函數中產生單個值。
控制權返回給調用者,但保留生成器的狀態,使得下次調用next()
時可以從上一次yield
的位置繼續執行。
如果將生成器放入循環語句中yield
可多次產生值
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
我可以這樣寫去實現:
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循環才能實現,有點難看...
引入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
用于在生成器函數(combined_generator)中委托部分生成任務給其他生成器(generator1,generator2), 而將子生成器的輸出直接傳遞給調用者,而不需要在主生成器中顯式循環子生成器的輸出。
更重要的是!!減少了循環的使用,減少了嵌套層次使得代碼更加簡潔。前提是你已經學會了這個語法。
有yield參與的賦值語句
先上代碼:
def generator_function():
value = yield "hello"
print(f"從yield接收的值是{value}")
yield value
有沒有感覺到一臉懵???為什么yield能用于賦值語句???
說好的yield
和return
類似能在函數中返回一個值,怎么還能用于賦值語句???

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