python 协程学习笔记

yield 生成器

from inspect import getgeneratorstate


def gen1():
    x = yield 2
    print(x)
    y = yield x
    return y

g = gen1()
print(getgeneratorstate(g))   # GEN_CREATED
# g.send(2)  # 直接send 非None 报错:TypeError: can't send non-None value to a just-started generator
g.send(None)  # 激活生成器
print(getgeneratorstate(g))    # GEN_SUSPENDED
g.send(2) 
print(getgeneratorstate(g))   # GEN_SUSPENDED
try:
    g.send(2)
except StopIteration as e:
    print('return value:', e.value)
    print(getgeneratorstate(g))   # GEN_CLOSED
  • 可以看到生成器有三个状态: GEN_CREATED、GEN_SUSPENDED、GEN_CLOSED
  • 如果向 GEN_CREATED send 非None,则会引发异常
  • 生成器结束时会引发 StopIteration 异常,如果有return 语句,则return 的值会保存在 异常的 value 信息中

此外,调用方还可以通过 throw 向生成器传递异常

def gen1():
    try:
        x = yield 2
        print(x)
        y = yield x
    except Exception:
        print('----Exception---')
    else:
        return y

g = gen1()
g.send(None)
g.throw(Exception)

运行结果

----StopIteration---
Traceback (most recent call last):
  File "/Users/Desktop/test/gen_test.py", line 16, in <module>
    g.throw(Exception)
StopIteration
  • 可以看到向生成器传递了StopIteration,随后生成器捕获了异常结束运行,并抛出StopIteration

yield from 委派生成器

from inspect import getgeneratorstate


def gen():
    x = yield from func1()
    print('gen x:', x)  # gen x: 10


def func1():
    x = yield 6
    print('f1 x:', x)   # f1 x: 1
    y = yield 8
    print('f2 y:', y)  # f2 y: 3
    return 10


print(type(func1()))
g = gen()
print(getgeneratorstate(g))
print(g)
r = g.send(None)
print('g:', r)  # g: 6
r = g.send(1)
print('g:', r)  # g: 8
try:
    r = g.send(3)
except StopIteration as e:
    print('e.value: ', e.value)  # e.value:  None
    print(getgeneratorstate(g))   # GEN_CLOSED
  • yield from 具有委派的作用,调用方通过委派生成器 gen 直接操作子生成器 func1
  • yield from 可以预激活生成器,调用方发送send(None)激活委派生成器 gen 时,yield from 预激活了func1,得到了 yield 返回的6
  • 子生成器的return 返回值会传递至委派生成器,return 的 10 成为 gen x 变量的值
  • 子生成器结束后,会抛出StopIteration异常,如果不处理,该异常会传递给调用方
  • yield from 后也可以 使用列表,字符串等, 可使用for循环获取值

asyncio 并发编程协程

import asyncio


@asyncio.coroutine
def func1():
    print(1)
    yield from asyncio.sleep(5)
    print(2)


@asyncio.coroutine
def func2():
    print(3)
    yield from asyncio.sleep(5)
    print(4)


tasks = [
    asyncio.ensure_future(func1()),
    asyncio.ensure_future(func2()),
]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

posted on 2022-11-19 14:39  每日问答  阅读(27)  评论(0)    收藏  举报

导航