场景

某一API端口每次最多只能接受长度为20的列表,现在有一个长度为76的列表需要分批次传入给API。

代码

1
2
3
4
5
6
def GenEveryTime(l: list, length=20):
"""将原来的列表每20个一组生成小列表的生成器"""
while len(l) > length:
yield l[:length]
l = l[length:]
yield l

验证

生成器的运作流程

生成器函数是一类特殊的函数。CPython解释器在遇到含有yield关键词的函数时会将这类函数看作生成器函数。生成器函数运行后会返回一个可迭代的生成器对象。
对一个生成器使用for循环next()方法时,生成器的内部代码会开始运行,直到yield关键词的那一行,返回yield之后的数值,就像return关键词那样。
但是,此时的生成器对象并没有消失,也不会被GC回收,当for循环运行到下一个循环的时候,生成器会从上一次被“中断”的状态开始继续运行。
生成器运行结束之后会raise一个迭代循环结束的异常,该异常一般会被for循环捕获并导致for循环退出。

生成器的用法

在上面的例子中,生成器首先开始了一个条件循环,并在这个循环中不断地yield出需要的数值;在这个条件循环结束之后,生成器还会进行最后一次yield,把剩余的数据yield出来。生成器内部维护一个列表对象l,用来存储没有被yield出去的剩余的列表。在for循环开始的时候,生成器首先判断剩下的数值是不是太长了,是不是需要分批次返回数值,如果需要就返回第一次的数值;如果剩下的数据很短不需要分批次,就直接把剩下的数据全都yield出去。

.send()

生成器还有一个send()方法,如果send参数为None,和直接对生成器使用next()方法是一致的;但如果外部代码send了一个非None的东西,生成器内部是可以捕捉到这个参数的,相当于一种在生成器运行过程中的传参,参数会被传入到yield左边,例如:

def foo():
    i = 0
    while 1:
        text: str = yield i
        print(text)
        i += 1

但是要注意参数的类型,最好直接用冒号标注出来。