基础知识

yieldyield from的使用

yield可以理解为产生一个值,在函数里使用,会把该函数变成generator,它和return的区别在于,yield在返回值之后,代码段不会直接结束,而是中断,同时下一次调用(send()和next()方法)的时候会从这次中断的地方继续执行,即保留了上下文。

def test():
    for i in range(3):
        print(f'yield start')
        yield i
        print('end of yield')

a = test()
print(next(a))
print(next(a))
print(next(a))
b = test()
print(next(b))

# Output:
yield start
0
end of yield
yield start
1
end of yield
yield start
2
yield start
0

当next(a)超出生成器范围时,会报StopIteration异常。

def test():
    for i in range(3):
        yield i

a = test()
print(next(a))
print(next(a))
print(next(a))

# Output:
0
1
StopIteration异常

可以用for来避免该异常

def test():
    for i in range(3):
        yield i

a = test()
for i in a:
    print(i)

# Output:
0
1

可以使用send()方法向generator中传值

def test():
    a = 0
    for i in range(3):
        b = yield a
        a = b + 1

gen = test()
print(gen)
print(next(gen)) # gen.send(None)等价于next(gen),这里必须先要第一次喂值
print(gen.send(1))
print(gen.send(10))

# Output:
0
2
11

查看生成器的状态

def simple_coro(a):
    print('-> Started: a=',a)
    b = yield a # 相当于是先返回a,暂停,直到next方法调用后,b赋值为send发送过来的数据,再执行到下一个yield暂停
    print('-> Received: b =',b)
    c = yield a+b # 先返回a+b,暂停,直到next方法调用后,c赋值为send发送过来的数据,再执行到下一个yield暂停
    print('-> Received: c=',c)

my_coro2=simple_coro(14) # 实例化一个协程对象

from inspect import getgeneratorstate # 得到状态的函数
print(getgeneratorstate(my_coro2))
next(my_coro2) 
print(getgeneratorstate(my_coro2))
my_coro2.send(28) 
my_coro2.send(99)   
# Outputs:
GEN_CREATED
-> Started: a= 14
GEN_SUSPENDED
-> Received: b = 28
-> Received: c= 99