协程之生成器

def gen_fun():
    #1. 可以产出值, 2. 可以接收值(调用方传递进来的值)
    html = yield  "http://projectsedu.com"
    print(html)
    yield 3
    yield 4
    yield 5
    return 'sunlong'

#1. 生成器不只可以产出值,还可以接收值
if __name__ == "__main__":
    gen = gen_fun()
    #在调用send发送非none值之前,我们必须启动一次生成器, 方式有两种1. gen.send(None), 2. next(gen)
    url = gen.send(None)
    print(url)
    html = 'sunlong88'
    #send方法可以传递值进入生成器内部,同时还可以重启生成器执行到下一个yield位置
    print(gen.send(html))
    print(next(gen))
    print(next(gen))
    #执行最后一个 找不到数据就会报错 StopIteration: sunlong
    print(next(gen))

 执行结果:

Traceback (most recent call last):
  File "E:/pythoncode/day07/04.py", line 17, in <module>
    print(next(gen))
StopIteration: sunlong
http://projectsedu.com
sunlong88
3
4
5

进程已结束,退出代码1

  

终止协程和异常处理:

close:

def gen_func():
    #1. 可以产出值, 2. 可以接收值(调用方传递进来的值)
    try:
        yield "http://projectsedu.com"
    except GeneratorExit :
        pass
        # raise StopIteration
    yield 2
    yield 3
    return "sunlong"

if __name__ == "__main__":
    gen = gen_func()
    print(next(gen))
    gen.close()
    # print("sunlong88")
    # print(next(gen))

执行结果:

http://projectsedu.com
Traceback (most recent call last):
  File "E:/pythoncode/day07/04.py", line 22, in <module>
    gen.close()
RuntimeError: generator ignored GeneratorExit
def gen_func():
    #1. 可以产出值, 2. 可以接收值(调用方传递进来的值)
    try:
        yield "http://projectsedu.com"
    except GeneratorExit :
        pass
        # raise StopIteration
    # yield 2
    # yield 3
    return "sunlong"

if __name__ == "__main__":
    gen = gen_func()
    print(next(gen))
    gen.close()
    # print("sunlong88")
    # print(next(gen))

上述代码中,注释了其他yield  ,再次执行就不会有异常了

http://projectsedu.com

进程已结束,退出代码0

  

或者捕获异常,并抛出StopIteration异常(表示已经运行到结尾了),这样也不会有报错

def gen_func():
    #1. 可以产出值, 2. 可以接收值(调用方传递进来的值)
    try:
        yield "http://projectsedu.com"
    except GeneratorExit :
        # pass
        raise StopIteration
    yield 2
    yield 3
    return "sunlong"

if __name__ == "__main__":
    gen = gen_func()
    print(next(gen))
    gen.close()
    # print("sunlong88")
    # print(next(gen))

总结close:

#gen.close() 致使生成器在暂停的yield表达式处抛出GeneratorExit异常。如果生成器处没有处理这个异常,
或者抛出StopIterration异常(运行到结尾),调用方不会报错。
如果收到GeneratorExit异常,生成器一定不能产出值,否则解释器会抛出RuntimeError异常,
生成器抛出的其他异常会向上冒泡,传给调用方
(要么不要去捕获异常,如果捕获了异常那么那么就请你抛出StopIterration异常(表示已经到了结尾了))

throw:

向生成器抛一个异常:

def gen_func():
    #1. 可以产出值, 2. 可以接收值(调用方传递进来的值)
    yield "http://projectsedu.com"
    yield 2
    yield 3
    return "bobby"

if __name__ == "__main__":
    gen = gen_func()
    print(next(gen))
    print(gen.throw(Exception, "download error"))

执行结果:
    http://projectsedu.com
    Exception: download error

改进一下(生成器自己捕获异常):

def gen_func():
    #1. 可以产出值, 2. 可以接收值(调用方传递进来的值)
    try:
        yield "http://projectsedu.com"
    except Exception as e:
        pass
    yield 2
    yield 3
    return "bobby"

if __name__ == "__main__":
    gen = gen_func()
    print(next(gen))
    print(gen.throw(Exception, "download error"))

执行结果:
    http://projectsedu.com
    2

总结:

throw会使生成器在暂停的yield表达式处抛出指定的异常,如果生成器处理了抛出的异常,

代码会向前执行到下一个yield表达式。而产生的值会成为调用throw方法得到的返回值,如果生成器没有处理抛出的异常,异常会向上冒泡,

传到调用方的上下文中

原文地址:https://www.cnblogs.com/sunlong88/p/9493981.html