【问题标题】:How to log that an iterator yielded n or zero times? [duplicate]如何记录迭代器产生 n 次或零次? [复制]
【发布时间】:2020-04-28 16:19:04
【问题描述】:

我想记录迭代器中事物的数量(而不是试图捕获一个空的迭代器,例如 this question),在我对它进行迭代并为每件事做了其他事情之后。

我的直觉是使用内置的enumerate:

def foo_yielder():
     to_yield = ['foo', 'bar']
     for x in to_yield:
         yield x

for i, x in enumerate(foo_yielder(), start=1):
    print(x)

# Now log how many things we printed
print(f"We logged {i} things")

但如果迭代器没有任何可以产生的东西,i 永远不会被定义。

如果这是 Javascript,我会这样做:

`We logged ${i || 0} things`

从 C 中吸取教训,我们可以做到:

i = 0
for x in foo_yielder():
    print(x)
    i = i + 1
print("We logged " + i + " things.")

但这似乎令人难以置信的蹩脚。

我可以在这里做一件优雅的事情吗?

【问题讨论】:

  • 我的特定用例与迭代数据库游标结果有关,如果查询没有返回结果该怎么办。
  • 为什么不把i = 0放在循环之前,如果循环没有破坏i,你会输出0?
  • 另一种选择是使用 if/else 语句进行设置,但仅定义 i 可能仍然是最佳选择。
  • 您也可以在for 循环中使用else 语句
  • @Gabip 我想让这个问题保持通用性。刚刚添加了一个用于刺激和愉悦的用例。

标签: python


【解决方案1】:

最简单的方法是在enumerate 循环之前添加一个i = 0。


如果麻烦的是 i = 0 附加行很难看,您可以尝试以下方法:

添加一个 "dummy" 迭代器并将 chain 它添加到您的迭代器中。然后,将enumerate 重置为从0 开始计数(作为默认值)。这样,您可以确保enumerate 将迭代至少一项(并将i 设置为0),然后从1 计算实际迭代器:

from itertools import chain

for i, x in enumerate(chain([0], foo_yielder())):
    pass
print(f"We logged {i} things")

这会带来另一个问题,即x 在第一次迭代中始终是 dummy。您可以使用循环内的条件来处理它,但这会使代码更加复杂。


最后,您可以用try/except 包装最终打印:

try:
    print(f"We logged {i} things")
except NameError:
    print(f"We logged 0 things")

但同样,这只是更多的代码,而不是简单的i = 0。

【讨论】:

    【解决方案2】:

    将其设置为枚举空列表,for 循环上的else 子句将始终在循环完成后执行,检查当前命名空间中是否存在i。插页式的 print 声明并不是真正需要的。我不知道它是否完全优雅,但它是 for-else 成语的一个很好的用例。

    for i, _ in enumerate([], start=1):
        pass # do whatever you want here
    else:
        if "i" in dir():
            print(f"Found {i} instances")
        else:
            print(f"Found instances")
    

    当然,这假设您没有在其他地方使用 i 作为变量

    当然,稍微干净一点(干,等等)

    for i, _ in enumerate([], start=1):
        pass # do whatever you want here
    else:
        if "i" not in dir():
            i = 0
    print(f"We logged {i} things")
    

    【讨论】:

    • 这里的 else 子句有什么好处?如果您完全删除 else,它会做同样的事情。
    • 我喜欢它明确地将行为绑定到循环中,这样如果将来进行更改,就可以更轻松地查看范围内的所有内容
    • else 仅在您 break 某处时才在语义上有用。 docs.python.org/3.6/tutorial/…
    • 我想我更喜欢你在 cmets @Andrew 中的回答设置 i = 0 然后使用枚举。
    猜你喜欢
    • 1970-01-01
    • 2013-09-21
    • 2017-07-05
    • 1970-01-01
    • 2016-01-20
    • 1970-01-01
    • 2011-11-18
    • 2017-12-01
    • 1970-01-01
    相关资源
    最近更新 更多