【问题标题】:For-loop first iteration over generator生成器上的 for 循环第一次迭代
【发布时间】:2019-06-05 06:51:13
【问题描述】:

我有一个生成器,它为我提供了熊猫数据框的“块”。我将块保存到 csv 文件中。

对于第一个“块”,我想禁用“mode='a'”,因为如果文件已经存在,我想覆盖该文件,应将以下块添加到新创建的文件中。

现在我已经用循环外的一个变量解决了它:“first”。

first = True
for chunk in generator:
    if first:
        chunk.to_csv(filename, sep=';')
        first = False
    else:
        chunk.to_csv(filename, sep=';', mode='a', header=False)

有没有更优雅的方式来处理生成器的第一个元素而不是其他元素?


我发现以下代码可以不同地处理列表中的第一个对象,但是它不适用于生成器对象。

seq= something.get()
foob( seq[0] )
for member in seq[1:]:
    foo( member )

尝试为生成器实现列表的代码给了我一个 TypeError('generator' 对象不可下标):

generator[0].to_csv(filename, sep=';')
for chunk in generator[1:]:
    chunk.to_csv(filename, sep=';', mode='a', header=False)

【问题讨论】:

    标签: python generator


    【解决方案1】:

    我会使用next。这样一来,您就不必在每次迭代时重复进行 if 检查(尽管可以忽略):

    first = next(generator)
    first.to_csv(filename, sep=';')
    for chunk in generator:  # will start from the second element
        chunk.to_csv(filename, sep=';', mode='a', header=False)
    

    【讨论】:

      【解决方案2】:

      这个怎么样:

      for i, chunk in enumerate(generator):
          chunk.to_csv(filename, sep=';', mode=('w' if i == 0 else 'a'), header=(i == 0))
      

      或者使用辅助变量:

      for i, chunk in enumerate(generator):
          first = i == 0
          chunk.to_csv(filename, sep=';', mode=('w' if first else 'a'), header=first)
      

      【讨论】:

      • 虽然我喜欢“单线解决方案”,但我想我会按照 DeepSpace 的建议选择“下一个”。这些文件很大,而且我有很多块,这意味着很多 if-checks。
      • if 检查是一个红鲱鱼。无论您有多少块,它们都会对整体运行时间做出精确的贡献
      • 磁盘 IO 在这种情况下是最慢的事情,在将块写入磁盘之间,您的程序将有数十亿个 CPU 周期空闲来执行任何数量的 if 检查。
      最近更新 更多