【问题标题】:Batch Generator function returns only last element when converted to list批处理生成器函数在转换为列表时仅返回最后一个元素
【发布时间】:2021-12-30 06:05:31
【问题描述】:

我有以下代码从项目列表中生成批次:

def batch_generator(items, batch_size):
    count = 1
    chunk = []
    
    for item in items:
        if count % batch_size:
            chunk.append(item)
        else:
            chunk.append(item)
            yield chunk
            chunk.clear()
        count += 1
    
    if len(chunk):
        yield chunk

逐一迭代会产生预期结果:

for x in batch_generator(range(17), 5):
    print(x)
# [0, 1, 2, 3, 4]
# [5, 6, 7, 8, 9]
# [10, 11, 12, 13, 14]
# [15, 16]

但是,当我直接将生成器转换为列表时,只返回最后一个元素,多次!

list(batch_generator(range(17), 5))
# [[15, 16], [15, 16], [15, 16], [15, 16]]

而转换为列表的简单生成器可以正常工作:

list(([i,i*2,i*3] for i in range(5)))
# [[0, 0, 0], [1, 2, 3], [2, 4, 6], [3, 6, 9], [4, 8, 12]]

为什么会这样?

【问题讨论】:

  • 每次在生成器中生成相同的列表对象(块),当您迭代它时,您会打印对象的当前内容,但是当您转换为列表时,您只有对同一个列表的多个引用.您应该创建一个空列表,而不是清除和重用同一个列表
  • 您返回的是同一个对象,chunk.clear() 就地改变了对象,因此更改会反映在所有列表中。使用 chunk = [] 而不是 .clear 应该会给您预期的结果。在带有 print 的 for 循环中,它看起来像预期的那样工作,但事实并非如此。如果您将它们存储在一个容器中,您会发现所有列表都是相同的。试试这个列表理解 out = [print(x) or x for x in batch_generator(range(17), 5)]; print(out) 里面的 print 语句打印正确的值,但 out 里面会有相同的值。

标签: python python-3.x generator yield


【解决方案1】:

chunk.clear() 是这里的问题。归根结底,返回的列表是多次返回的同一个列表。

chunk.clear() 替换为chunk = []。这样chunk 将是列表的不同实例:

【讨论】:

    【解决方案2】:

    您可以使用chunk[:]list(chunk) 生成块的副本。而不仅仅是yield chunk

    【讨论】:

      猜你喜欢
      • 2021-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 2016-01-30
      相关资源
      最近更新 更多