生成器的一大特点:可以实现暂停,从生成器到协程,还有一些问题需要解决。
def gen_func():
yield 1
yield 2
yield 3
return "Tom"
if __name__=="__main__":
gen = gen_func() # 生成生成器对象
print(next(gen)) #1 # 生成器实现了迭代协议,可用直接是由next
print(next(gen)) #2
print(next(gen)) #3
print(next(gen)) # 抛出异常,"StopIteration: Tom",停止迭代,并返回值Tom
生成器的特性:
1. 生成器不止可以产生值,还可以接收值
def gen_func():
html1=yield "http://www.baidu.com" # 该段代码的含义:1.可用产出值;2.可用接收值(调用方传递回来的值)
print(html1) # 调用方返回的值可以传递到生成器内部,获取值后打印值。打印输出Tom
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
url = next(gen)
# download url
html1 = "Tom"
gen.send(html1) # send方法可以传递值进入生成器内部,同时还可以重启生成器执行到下一个yield位置。
# 任何时候,任何地方只要拿到生成器对象就可以对它进行操作,包括暂停/恢复,要将值传递进去,就不可用next方法,next适用于直接yield值的场合。
#1. 启动生成器的方法有两种,next() 与 send(),send可用将值发送到内部,同时启动生成器。
既然send方法与next方法有相同的效果,则:
def gen_func():
html1=yield "http://www.baidu.com" # 该段代码的含义:1.可用产出值;2.可用接收值(调用方传递回来的值)
print(html1) # 调用方返回的值可以传递到生成器内部,获取值后打印值。打印输出Tom
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
url = next(gen)
# download url
html1 = "Tom"
print(gen.send(html1)) # 2 执行的结果与print(next(gen))的结果一样,yield 2
调用send方法
def gen_func():
html1=yield "http://www.baidu.com" # 该段代码的含义:1.可用产出值;2.可用接收值(调用方传递回来的值)
print(html1) # 调用方返回的值可以传递到生成器内部,获取值后打印值。打印输出Tom
yield 2
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
# 在调用send发送非None值之前,我们必须启动一次生成器,方式有两种:1.直接调用gen.send(None),2.next(gen)
# url = gen.send(gen) # TypeError: can't send non-None value to a just-started generator
url = gen.send(None) # 生成器第一次执行时,不能send一个非None的值,只能send None,为什么?
# send方法将值发送给”html1“这个对象,生成器初始化时只是一个生成器对象,如果刚开始时根本没有执行过生成器,就无从运行到
# “html1=yield "http://www.baidu.com"”这一行代码,所以send一个非None的值进来时,系统就会报错。
# download url
html1 = "Tom"
print(gen.send(html1)) # 2 执行的结果与print(next(gen))的结果一样,yield 2
# print(gen.send(html1)) # 由于上面只yield了一次,如果再次调用该语句就会抛出异常
close
def gen_func():
yield "http://www.baidu.com"
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
print(next(gen)) # http://www.baidu.com,它会在执行yield "http://www.baidu.com"语句
# 后抛出异常, 抛出StopIteration异常
gen.close()
next(gen)
def gen_func():
try:
yield "http://www.baidu.com"
except GeneratorExit:
pass # 调用gen.close()后,不管有没有catch到异常,生成器已经结束,他就会抛出异常。
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
print(next(gen))
gen.close() # 抛出 RuntimeError: generator ignored GeneratorExit,已经将GeneratorExit忽略掉了
next(gen)
def gen_func():
try:
yield "http://www.baidu.com"
except GeneratorExit:
raise StopIteration
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
print(next(gen))
gen.close() # 此时,close就不会抛出异常
next(gen) # 由于注释掉yield 2/yield 3,在调用next(gen)方法时抛出异常,StopIteration,已经将GeneratorExit忽略掉了
def gen_func():
yield "http://www.baidu.com"
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
print(next(gen))
gen.close() # 此时,close不会抛出异常
next(gen) # 只有在再次调用是才抛出异常,StopIteration
def gen_func():
try:
yield "http://www.baidu.com"
except GeneratorExit:
pass
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
print(next(gen))
gen.close() # 由于前面有了try/catch,执行到gen.close()就会抛出异常,RuntimeError: generator ignored GeneratorExit
print("Hello") # 该代码不会被执行
# 异常会反映到调用方gen.close()里面,即调用close的地方抛出异常。gen.close()后面的代码不会被执行。
def gen_func():
try:
yield "http://www.baidu.com"
except Exception: # 此处不去处理GeneratorExit异常,后面就不会抛出异常,代码均可执行
pass
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
print(next(gen)) # http://www.baidu.com
gen.close()
print("Hello") # hello
为什么?GeneratorExit 是继承至BaseException,不是Exception
def gen_func():
try:
yield "http://www.baidu.com"
except BaseException:
pass
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
print(next(gen)) # http://www.baidu.com
gen.close() # 此时继续抛出RuntimeError: generator ignored GeneratorExit
print("Hello") # 该语句不被执行
Throw方法
def gen_func():
yield "http://www.baidu.com"
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
print(next(gen)) # http://www.baidu.com
gen.throw(Exception,"Download Error!") # Exception: Download Error!
def gen_func():
try:
yield "http://www.baidu.com"
except Exception as e:
pass
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
print(next(gen)) # http://www.baidu.com
gen.throw(Exception,"Download Error!") # 可以顺利执行,并没有报错
print(next(gen)) # 3
def gen_func():
try:
yield "http://www.baidu.com"
except Exception as e:
pass
yield 2
yield 3
return "Tom-1"
if __name__=="__main__":
gen = gen_func()
print(next(gen)) # http://www.baidu.com
gen.throw(Exception,"Download Error!") # 可以顺利执行,并没有报错
print(next(gen)) # 3
gen.throw(Exception,"Download Error!") # Exception: Download Error!