yield 是产出的意思,就是返回一个值,这一点有点像return,但是不会结束函数的执行。那它什么时候继续执行呢?等待下一次迭代器被调用时候返回上次中断的地方,
利用这个特性可以实现range函数:
def my_range(max_num):
i = 0
while i < max_num:
yield i # 从此出产出i,下次调用时,从这里继续
i = i + 1
for v in my_range(10): # 带有yield 的函数调用后是个生成器对象,可迭代的
print(v)
输出:
0
1
2
3
4
5
6
7
8
9
使用内置next
方法可以调用生成器,可以运行到下一个yield,还可以使用生成器自带的send方法调用它,并且还可以往函数内部传值:
def f1():
i = 0
while 1:
x = yield i
print(f"x is {x}")
gen = f1()
next(gen) # 预激活生成器
gen.send('hh') # 发送的字符串赋值给了 f1函数中的x,也就是yield的赋值语句
输出:
x is hh
貌似没啥用,可以用这个写一个计算平均值的程序,每次使用send发送给生成器一个数字,生成器返回所有数字的平均值:
def average():
count = 0
total = 0
ave = None
while 1:
new_num = yield ave
count = count + 1
total = total + new_num
ave = total / count
gen = average()
gen.send(None)
print(gen.send(1))
print(gen.send(2))
print(gen.send(3))
输出:
1.0
1.5
2.0
用一个yield 调用另外一个yiled会返回什么呢?
def f1():
yield 100
def f2():
yield f1()
if __name__ == '__main__':
gen = f2()
print(next(gen))
输出:
<generator object f1 at 0x10a855650>
输出f1的生成器,调用完f1() ,生成一个生成器然后在f2里面被yield出去了,那能不能获取f1生成器中的内容yield出去?可能要这么写:
def f1():
yield 100
def f2():
yield next(f1())
if __name__ == '__main__':
gen = f2()
print(next(gen))
输出:
100
它还提供了一种专用的方法, yield from
:
def f1():
yield 100
def f2():
yield from f1()
if __name__ == '__main__':
gen = f2()
print(next(gen))
yield from
可以yield别的生成器的内容,有人把 带yield from
的生成器叫委托生成器,真正的生成器叫子生成器,而且还可以通过委托生成器调用子生成器:
def f1():
x = yield 100
print(f"x is {x}")
def f2():
yield from f1()
if __name__ == '__main__':
gen = f2()
print(next(gen))
gen.send('hhh') # 实际上发送给 f1的生成器了
输出:
Traceback (most recent call last):
File "/Users/wuhf/PycharmProjects/cookdata/cookdata/web/test/run_yield6.py", line 13, in <module>
gen.send('hhh')
StopIteration
100
x is hhh