yield把函数变为generator gennerator需要收到一次send(None)或者next才开始执行函数 函数执行了yield语句后,会挂起,直到外部调用send传递一个对象作为yield语句返回值,则继续函数 generator中如果执行return语句也会向常规函数一样终止 yield会执行完下一条语句后,挂起这个方法,保存该语句结果 直到外部调用next或者send才继续方法的执行 比如下面例子
def Test3():
print("Test3 in")
for i in range(3):
s = yield print("do yield test3 %s" % i)
print("Test3 get %s" % s)
print("Test3 end")
print("start3")
t = Test3()
print("start3 send")
t.send(None)
print("start3 send end")
for i in range(2):
print("start3 range %s" % i)
t.send(i)
print("start3 range end")
"""
--------------------------OUTPUT---------------------
start3
start3 send
Test3 in
do yield test3 0
start3 send end
start3 range 0
Test3 get 0
do yield test3 1
start3 range 1
Test3 get 1
do yield test3 2
start3 range end
"""
未终止的generator(还有yield挂起在等待send)也可以通过调用close方法强行终止
yield from 迭代器等价于
for xx in 迭代器:
yield xx
因为next(g)等价于g.send(None)
class Generator(Iterator):
__slots__ = ()
def __next__(self):
return self.send(None)
所以可以这样写
def Test():
r = yield from [1,2,3,4,5]
print("t %s" % r)
g = Test()
for i in range(5):
print(next(g))
再看看嵌套使用的例子
def InnerYieldPrint(i):
print("inner yield %s" % i)
return i
def InnerYield():
print("InnerYield")
for i in range(5):#因为是5所以算上启动要外部发送6次
s = yield InnerYieldPrint(i)
print("inner get %s" % i)
print("Test2 give inner %s" % s)
print("InnerYield end")
yield 99#因为send每次都要执行到下一个yield语句,才算结束,不然会抛出异常
def Test():
yield from InnerYield()
print("yield from end")
def Test2():
"""等价于Test"""
print("Test2")
x = InnerYield()
print("go die")
iCnt = 0
for r in x:#等价于 r = next(x),那么第一次就是启动InnerYield
iCnt += 1
print("cnt %s" % iCnt)
print("prepare Test2 %s" % r)
if iCnt >= 6:
print("break")
break
s = yield r#这里返回作为外面的send返回值了
print("Test2 %s" % s)
print("yield from end")
yield 999#因为send每次都要执行到下一个yield语句,才算结束,不然会抛出异常
g = Test2()
print("start")
print(g.send(None)) # 启动Test2
for i in [-1, -2, -3, -4, -5,]:
print("pro %s" % i)
print("pro send res %s" % g.send(i))
"""
--------------------------OUTPUT---------------------
start
Test2
go die
InnerYield
inner yield 0
cnt 1
prepare Test2 0
0
pro -1
Test2 -1
inner get 0
Test2 give inner None
inner yield 1
cnt 2
prepare Test2 1
pro send res 1
pro -2
Test2 -2
inner get 1
Test2 give inner None
inner yield 2
cnt 3
prepare Test2 2
pro send res 2
pro -3
Test2 -3
inner get 2
Test2 give inner None
inner yield 3
cnt 4
prepare Test2 3
pro send res 3
pro -4
Test2 -4
inner get 3
Test2 give inner None
inner yield 4
cnt 5
prepare Test2 4
pro send res 4
pro -5
Test2 -5
inner get 4
Test2 give inner None
InnerYield end
cnt 6
prepare Test2 99
break
yield from end
pro send res 999
"""
这里比较奇特的是,外层函数的yield可以对应里层generator的send,反之不行 所以InnerYield中的yield 99可以改为return 99而Test2中的yield 999不能改为return