盘点那些不为人知的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的状态(作用)。