yield 关键字
yield
关键字只能出现在函数体中,它用于将函数转变成一个生成器。
当需要从生成器中取值时,程序会执行到 yield
关键字出现的位置,将 yield
返回给调用方,并暂停生成器函数的执行;当下次再从生成器中取值时,从上次暂停的地方继续执行。
因此,yield
实际上提供了一个 lazy 的序列,其值是在调用方真正获取值时才生成的。它无需预先将整个序列加载到内存中,在遍历大序列时可以明显节约内存资源。
# 基本用法
# 取值
使用 yield
定义一个生成器,并从中取值:
def generate_value():
print('generator staring...')
yield 1
print('generator ending...')
# 调用包含 yield 关键字的函数,会得到生成器
generator = generate_value()
# 首次从生成器中取值,取值后生成器将暂停执行
print('first value: %s' % (next(generator)))
print('now, start to get second value...')
# 第二次从生成器中取值,将从上次暂停的点继续执行
# 由于生成器中已经没有多余元素,此时会抛出StopIteration
print('second value: %s' % (next(generator)))
执行输出为:
generator staring...
first value: 1
now, start to get second value...
generator ending...
Traceback (most recent call last):
File "a.py", line 10, in <module>
print('second value: %s' % (next(generator)))
StopIteration
# 遍历
- 可以使用
for循环
遍历yield
生成器 - 可以使用
yield
生成器构建list
等容器
# 一个函数中可以出现多个 yield 关键字,每取一次值就执行到一个 yield。
def generate_value_1():
yield 1
yield 2
def generate_value_2(num):
cnt = 0
while cnt < num:
yield cnt
cnt += 1
generator_1 = generate_value_1()
print('iterator generator...')
for i in generator_1:
print(i)
print('get list from generator: %s' % (list(generate_value_2(3))))
输出为:
iterator generator...
1
2
get list from generator: [0, 1, 2]
# 与 return 共存
yield
关键字可以和 return
关键字共存在一个函数体内。当执行到 return
语句时,退出函数。
# 定义一个生成器,最多只能生成 max 个元素
def generator_value(num, max=5):
cnt = 0
while cnt < num:
if cnt == max:
return
else:
yield cnt
cnt += 1
print(list(generator_value(10)))
输出为:
[0, 1, 2, 3, 4]
# 高级用法
yield
生成器对象具有一个特殊的方法叫做 send()
,它可以用于在生成器的暂停状态下发送值,并作为 yield
表达式的结果。这种双向通信的能力可以用于在生成器与外部环境之间进行数据交换和协调。
# 基本用例
def generate_value():
# 生成器首次执行时,到此处暂停,等待接受 send() 传递的值
# 接受成功后,将接收到的值赋给等号左边的变量,并继续向下执行
value = yield
# 将计算结果返回调用方
yield value + 1
generator = generate_value()
# 启动生成器
next(generator) # 首次通过 next() 或者 send(None) 以启动生成器
# 使用 send() 发送数据并获取结果
print(generator.send(10))
输出为:
11
生成器和外部环境可以双向通信,可用于一些高级功能的实现,如:
- 控制生成器的执行流程
- 实现协程和状态机
# 控制生成器的执行流程
如下示例中,可以通过外部变量控制生成器内部计数器的增减:
def counter():
i = 0
while True:
command = yield i # 返回 i 的值,并在此处等待 send() 发送的值,一旦接受到,将其赋给 command,并继续执行
if command == 'increment':
i += 1
elif command == 'decrement':
i -= 1
# 创建生成器对象
gen = counter()
# 启动生成器,执行到第一个 yield
next(gen)
# 控制生成器的执行流程
print(gen.send('increment')) # 输出:1
print(gen.send('increment')) # 输出:2
print(gen.send('decrement')) # 输出:1
# 实现状态机
如下示例中,模拟一个简单的状态机,根据当前的状态和接收到的事件进行状态转换。通过发送不同的事件,可以控制状态机在不同的状态之间切换。
def state_machine():
state = 'INIT'
while True:
event = yield state
if state == 'INIT':
if event == 'start':
state = 'RUNNING'
elif state == 'RUNNING':
if event == 'stop':
state = 'STOPPED'
elif state == 'STOPPED':
if event == 'reset':
state = 'INIT'
# 创建生成器对象
sm = state_machine()
# 启动生成器,执行到第一个 yield
next(sm)
# 控制状态机的状态转换
print(sm.send('start')) # 输出:'RUNNING'
print(sm.send('stop')) # 输出:'STOPPED'
print(sm.send('reset')) # 输出:'INIT'
上次更新: 2023/12/08, 06:34:37