用于计算循环执行的Python习惯用法

时间:2017-02-13 15:00:19

标签: python for-loop idioms idiomatic

如果循环遍历list / tuple / sequence,则可以使用len(...)来推断循环执行的次数。但是当循环遍历迭代器时,你不能。

[为清晰起见更新:我正在考虑一次性使用有限迭代器,我想对项目进行计算并同时计算它们。]

我目前使用显式计数器变量,如下例所示:

def some_function(some_argument):
    pass


some_iterator = iter("Hello world")

count = 0
for value in some_iterator:
    some_function(value)
    count += 1

print("Looped %i times" % count)

鉴于"Hello world"中有11个字符, 这里的预期输出是:

Looped 11 times

我还使用enumerate(...)考虑了这个较短的替代方案,但我没有发现这一点:

def some_function(some_argument):
    pass


some_iterator = iter("Hello world")

count = 0  # Added for special case, see note below
for count, value in enumerate(some_iterator, start=1):
    some_function(value)

print("Looped %i times" % count)

[更新以供参考:@mata发现,如果迭代器为空,那么最初编写的第二个示例将失败。插入count = 0解决了这个问题,或者我们可以使用for ... else ...结构来处理此案例。]

它不使用循环中enumerate(...)的索引,而是将变量设置为循环计数几乎是一个副作用。对我来说这是非常不清楚的,所以我更喜欢第一个带有显式增量的版本。

是否有可接受的Pythonic方法(理想情况下是Python 3和Python 2代码)?

4 个答案:

答案 0 :(得分:5)

如果循环没有通过添加一行来运行,您可以将enumerate的便利性与定义的计数器结合起来:

count = 0  # Counter is set in any case.
for count, item in enumerate(data, start=1):
   doSomethingTo(item)
print "Did it %d times" % count

如果只需要计算迭代器中的项目数,而不对项目做任何事情,并且没有列出它们,那么你可以简单地做到:

count = sum(1 for ignored_item in data)  # count a 1 for each item

答案 1 :(得分:2)

你可以做各种各样的事情来计算发电机中的物品数量,但无论如何,原来的发电机都会被浪费掉。精确地说,精疲力竭。

length = sum(1 for x in gen)
length = max(c for c, _ in enumerate(gen, 1))
length = len(list(gen))
  1. 这里显示的第一种方式非常好,因为它处理具有空发生器井的情况并且按预期返回零。
  2. 当给出耗尽的生成器时,第二个代码将引发异常,这在它永远不会耗尽时可能很有用,但它实际上是,因此执行将停止并且您将能够调查出错的地方
  3. 如果gen提供的数据太大,此代码可能会浪费大量内存,但它很容易理解,因此没有人会不得不认真思考墙试图了解这意味着什么。
  4. 所有这些仅适用于有限生成器。

    如果你想计算长度'迭代器在循环它时,你可以这样做:

    length = 0
    for length, data in enumerate(gen, 1):
        # do stuff
    

    现在,length将等于生成器生成的元素数量。请注意,您不必手动增加length,因为lengthdata在循环执行后仍然可用且有效。

    编辑:如果你想为每个值执行一些函数并忽略它的返回值(你可以通过使用列表作为函数的参数之一来处理它),你可以试试这个:

    length = sum(1 | bool(function(x)) for x in gen)
    

    这将计算将function应用于生成器的每个元素时的长度。尽管如此,使用enumerate看起来更好。

答案 2 :(得分:1)

无法获取迭代器中的项目数。想想这个案例

def gen():
   a = 1
   while True:
       yield a
       a += 1
f = gen()

for value in f:
    # do something

这个迭代器的大小是多少?迭代器结束时,如果,它会引发StopIteration。相反,当您遍历序列时,序列已经存在,因此可以知道其长度。

你使用的两种方法都很好。 best 取决于您的口味。另一种选择是使用

from itertools import count
for item, counter in zip(iterator, count()):
    # do stuff

但是,我认为在大多数情况下,您的第一种传统方法会更清晰。

答案 3 :(得分:0)

这有什么问题?

len(list(some_iterator))