1. generator.next()、generator.send(value)
generator.next():开始执行一个generator函数或者从上次执行yield表达式的地方从新开始执行generator函数。当generator函数通过next()函数继续执行时,当前的yield表达式总得值总是None。此时,这个generator函数继续执行到下一个yield表达式的地方,然后挂起,同时将yield表达式的值返回。如果generator函数后面如果没有yield表达式了,就抛出一个StopIteratio。
generator.send(value):继续执行一个generator函数。当generator函数通过send()函数继续执行时,value这个参数变成了当前的yield表达式的值。此时,这个generator函数继续执行到下一个yield表达式的地方,然后挂起,同时将yield表达式的值返回。如果generator函数后面没有yield了,会抛出StopIteration异常。当调用send()来启动generator的时候,value这个参数必须是None,因为这个时候没有yield表达式来接受参数。
def gen_fun():
yield 1
print(11)
a = yield 2
print(a)
yield (3)
print(31)
return "success"
if __name__ == '__main__':
gen = gen_fun()
print(next(gen))
print(next(gen))
a = 5
print(gen.send(a))
try:
print(next(gen))
except StopIteration as e:
print(e.value)
"""
运行结果:
1
11
2
5
3
31
success
"""
"""
next(): 开始执行一个generator函数或者从上次执行yield表达式的地方从新开始执行generator函数。当
generator函数通过next()函数继续执行时,当前的yield表达式总得值总是None。此时,这个generator
函数继续执行到下一个yield表达式的地方,然后挂起,同时将yield表达式的值返回。如果generator函数
后面如果没有yield表达式了,就抛出一个StopIteratio。
send(): 继续执行一个generator函数。当generator函数通过send()函数继续执行时,value这个参数变成了当前
的yield表达式的值。此时,这个generator函数继续执行到下一个yield表达式的地方,然后挂起,同时将
yield表达式的值返回。如果generator函数后面没有yield了,会抛出StopIteration异常。当调用send()
来启动generator的时候,value这个参数必须是None,因为这个时候没有yield表达式来接受参数。
"""
"""
获取生成器返回结果必须进行异常处理。
"""
2. generator.throw(type[, value[, traceback]])
yield 在生成器中可以接收到通过 gen.throw() 抛出的异常,并且会将这个异常抛出到生成器的调用方。具体来说,当调用 gen.throw() 方法并传入一个异常时,生成器会在当前的 yield 语句处抛出这个异常。
这样的机制可以让生成器和调用方之间进行异常的交互,使得生成器可以处理调用方发送过来的异常,也可以根据需要选择是否继续执行或结束生成器。
以下是一个示例代码,演示了如何在生成器中通过 yield 抛出通过 gen.throw() 传入的异常:
def my_generator():
while True:
try:
value = yield
print("Received value:", value)
except ValueError as e:
print("Caught ValueError in generator:", e)
# 可以在这里做一些处理,然后决定是否继续生成器的执行
# 如果不想继续生成器的执行,可以使用 raise 语句将异常再次抛出
raise
gen = my_generator()
next(gen) # 启动生成器
try:
gen.throw(ValueError("Custom error message"))
except StopIteration:
print("Generator has finished")
3. generator.close()
generator.close():在生成器函数挂起的地方抛出一个 GeneratorExit 异常。这并不等价于 generator.throw(GeneratorExit),后面会说原因。
如果生成器抛出 StopIteration 异常(不管是由于正常退出还是因为该生成器已经关闭),或者抛出 GeneratorExit 异常(不捕获该异常即可),close 方法不传递该异常,直接返回到调用方。而生成器抛出的其他异常会传递给调用方。
GeneratorExit 异常的产生意味着生成器对象的生命周期已经结束,因此生成器方法后续语句中不能再有 yield,否则会产生 RuntimeError。(而 throw 方法是期待一个 yield 返回值的,如果没有,则会抛出 StopIteration 异常。)
对于已经正常退出或者因为异常退出的生成器对象,close 方法不会进行任何操作。
(i) 不捕获 GeneratorExit 异常,close 方法返回调用方,不传递该异常。
def gen():
print('下面 yield 1')
yield 1
print('下面 yield 2')
yield 2
g = gen()
next(g)
g.close()
"""
运行结果:
下面 yield 1
"""
print()
next(g)
"""
运行结果:
Traceback (most recent call last):
File "test.py", line 15, in <module>
next(g)
StopIteration
"""
"""
注意:对已经关闭的生成器对象使用 next 会抛出 StopIteration 异常。
"""
(ii) 生成器自然退出抛出 StopIteration 异常,该异常不会传递给调用方,close 方法正常返回。
def gen():
try:
yield 1
except GeneratorExit:
print('捕获到GeneratorExit')
print('生成器函数结束了')
g = gen()
print(next(g))
g.close()
"""
运行结果:
1
捕获到GeneratorExit
生成器函数结束了
"""
(iii) 在 GeneratorExit 抛出后还有 yield 语句,会产生 RuntimeError。另外生成器对象被垃圾回收时,解释器会自动调用该对象的 close 方法(PEP 342),这意味着最好不要在相应的 except 和 finally 中写 yield 语句,否则不知道什么时候就会抛出 RuntimeError 异常。
def gen():
try:
yield 1
except GeneratorExit:
print('捕获到 GeneratorExit')
print('尝试在 GeneratorExit 产生后 yield 一个值')
yield 2
print('生成器结束')
g = gen()
next(g)
g.close()
"""
运行结果:
捕获到 GeneratorExit
尝试在 GeneratorExit 产生后 yield 一个值
Traceback (most recent call last):
File "test.py", line 14, in <module>
g.close()
RuntimeError: generator ignored GeneratorExit
"""
一种防止抛出 RuntimeError 的安全生成器写法:设置一个布尔标识。
def safegen():
yield 'so far so good'
closed = False
try:
yield 'yay'
except GeneratorExit:
closed = True
raise
finally:
if not closed:
yield 'boo'
(iv) 对已经关闭的生成器对象调用 close() 方法,不会进行任何操作。
def gen():
yield 1
print('我不会被执行')
print('因为在 yield 1 就抛出了 GeneratorExit 异常')
print('未经捕获的 GeneratorExit 异常不会传递')
print('返回执行权给 close 的调用方')
g = gen()
g.close()
g.close()
g.close() # 多次调用 close,什么效果都没有
补充:GeneratorExit 异常只有在生成器对象被激活后,才有可能产生。
def gen():
try:
yield 1
except GeneratorExit:
print('捕获到 GeneratorExit')
raise
g1 = gen()
next(g1)
g1.close()
"""
运行结果:
捕获到 GeneratorExit
"""
# 没有激活生成器,就不会触发 GeneratorExit 异常
print()
g2 = gen()
g2.close()
print('脚本运行完毕')
"""
运行结果:
脚本运行完毕
"""
[参考博客]https://blog.csdn.net/jpch89/article/details/87036970
http://blog.chinaunix.net/uid-17260303-id-2811335.html