如何从多个项目的缓冲区中产生单个项目并定期重新填充缓冲区?

时间:2019-03-09 18:34:15

标签: python queue generator

我有一个很大的数据源,可以逐块提取数据。
我不想通过返回一个生成器来返回一个chunksize块,而是想通过生成器来生成单个项,并且一旦我从一个块中获取了所有数据,就想加载下一个块。
目标是一次返回一个项目,而不加载完整的数据源,而且也不会从数据源中一一拉出这些项目。

这是一些伪代码:

def get_data_chunk(datasource, chunksize=10):
    # grab chunksize elements of datasource
    return data_chunk # a list of dict, usually

def generator(datasource):
    data_chunk = get_data_chunk(datasource)
    for item in data_chunk:
        yield item
    # if no more item in data_chunk, reload from get_data_chunk
    # until datasource does not return anything

我尝试使用一个队列,该队列一旦被清空就重新填充,但是没有成功。

1 个答案:

答案 0 :(得分:2)

您有两个选择:

  1. 使用while True:循环并在下一个块为空时退出:

    def generator(datasource):
        while True:
            data_chunk = get_data_chunk(datasource)
            if not data_chunk:
                return
            for item in data_chunk:
                yield item
    
  2. for循环中使用iter() function的两个参数形式:

    def generator(datasource):
        for data_chunk in iter(lambda: get_data_chunk(datasource), None):
            for item in data_chunk:
                yield item
    

    或使用itertools.chain.from_iterable()

    from itertools import chain
    
    def generator(datasource):
        chunk_iter = iter(lambda: get_data_chunk(datasource), None)
        yield from chain.from_iterable(chunk_iter)
    

后者要求您知道“最终值”是什么样子。在上面,我假设最终值是None,但是如果它是一个空列表,则需要将None替换为[]

演示:

>>> from itertools import chain, islice
>>> from random import randrange
>>> demosource = (randrange(11, 81) for _ in range(17))
>>> def get_data_chunk(datasource, chunksize=10):
...     return list(islice(datasource, chunksize))
...
>>> def generator(datasource):
...     chunk_iter = iter(lambda: get_data_chunk(datasource), [])  # last chuck is an empty list
...     yield from chain.from_iterable(chunk_iter)
...
>>> list(generator(demosource))
[38, 47, 74, 13, 23, 24, 47, 61, 30, 38, 70, 41, 43, 47, 37, 34, 67]