生成器函数进阶
首先,先看一个实例:
def generator():
print(123)
content = yield 1
print('generatorNum',num)
print(456)
yield 2
#生成一个生成器
g = generator()
#ret = g.send("函数") #调用send()函数取值,此时会报错,关于send()函数及报错的原因后面再说
#调用__next__()函数取值
ret = g.__next__() #结果为:输出123,ret或的值为1
#调用send()函数取值
ret = g.send("mmx") #结果为:输出generatorNum,mmx,456;ret获得的结果为2
send()函数: 从上面可以看到send()函数也可以用来获取生成器中的值,并且用其获取生成器中值的效果和next基本一致,不同的地方在于用send()函数获取下一个值的时候,给上一yield的位置传递一个数据,这个数据即为传给send()函数的参数。
注意: 从上面很容易看出,第一次使用生成器的时候,必须要用__next__()获取下一个值,第二次获取值的时候才可以使用send()方法;并且最后一个yield不能接收外部的值,如果最后一个yield确实还需要实现一些功能,可以按如下的样式来写:
def generator():
功能代码块
cont1 = yield 返回值 #第一个yield
功能代码块
cont2 = yield 返回值 #第二个yield
功能代码块
yield 返回值 #最后一个yield
功能代码块
yield #这里不加返回值即可
生成器函数的实例
1、这是一个求平均数的例子,其功能是:第一次调用时,求0的平均数,第二次调用传入一个值,求0和这个值的平均数,第三次同样传入一个数,求着三个数的平均数,…,依次类推。
def avger():
sum = 0
count = 0
avg = 0
while 1:
num = yield avg
sum += num
count += 1
avg = sum/count
g = avger() #生成生成器
ret = g.__next__() #求得0的平均数0
ret = g.send(20) #求的0与20的平均数
ret = g.send(30) #求得0、20与30的平均数
2、带有装饰器的生成器示例——预激生成器
本例是对上一个例子的一个补充,在上例中,当生成器生成后,首次必须使用__next__()来进行一个初始化,然后才能用send传值,这里将用装饰器来装饰次函数,让第一次的__next__()自动执行。
#装饰器
def des(func):
def inner(*args,**kwargs):
g = func(*args,**kwargs)
g.__next__() #自动调用__next__()
return g
return inner
#生成器
@des
def avger():
sum = 0
count = 0
avg = 0
while 1:
num = yield avg
sum += num
count +=1
avg = sum/count
#由于装饰器的作用,这次便可直接使用send()方法
g = avger()
ret = g.send(20)
ret = g.send(30) #此时ret的结果为25.0
ret = g.send(40) #此时ret的结果为(40+20+30)/3
预激生成器 就是指的类似于本例中的这种生成器,不需要自己手动初始化,而使用装饰器来自动执行__next__()方法来激活。
yield from关键字
这个关键字后面跟的是一个容器,此关键字可以将容器中的所有值挨个取出来,具体的将在实例中展开:
def generater():
a = 'abcd'
b = '1234'
yield from a#用在生成器当中,从容器a中返回一个一个的值,
#后面只能跟一个值
yield from b
#上面的代码等价于:
def generater():
a = 'abcdc'
b = '12345'
for i in a:
yield i
for j in b:
yield j