如何判断一个可迭代对象是否只能被迭代一次?

时间:2020-01-03 03:18:23

标签: python iterator iterable

生成器之类的可迭代项只能被迭代一次:

def f():
  for i in range(10):
    yield i
a = f()
for x in a:
  print(x) # prints x
for x in a:
  print(x) # prints none

list这样的可迭代对象可以被迭代很多次:

a = list(range(10))
for x in a:
  print(x) # prints x
for x in a:
  print(x) # prints x

我怎么知道一个可迭代对象只能被迭代一次?

此问题的动机来自itertools.cycle的实现:

def cycle(iterable):
    # cycle('ABCD') --> A B C D A B C D A B C D ...
    saved = []
    for element in iterable:
        yield element
        saved.append(element)
    while saved:
        for element in saved:
              yield element

如果我们可以判断一个Iterable是否只能被迭代一次,则可以使实现的内存效率更高:

def cycle(iterable):
    it = iterable
    if only_iterated_once(iterable):
       it = list(iterable)
    while True:
        for element in it:
              yield element

如果该参数可以重复多次,则无需保存其他副本。

1 个答案:

答案 0 :(得分:4)

示例之间的主要区别在于,在生成器示例中,在循环发生之前创建了一个迭代器,然后将该相同的迭代器使用了两次。但是,在清单示例中,每个循环都使用一个新的迭代器。


在第一个示例中,生成器本身就是迭代器。当你做

a = f()

f的调用将创建一个生成器(它是一个迭代器)。当您将a赋予for循环时,它们会在iter上调用a,它会返回自身。简短的MCVE轻松显示了这一点:

l = [1]
i = iter(l)

j = iter(i)

print(i is j)  # Prints True

两个循环都使用一个迭代器。这意味着到第二个循环开始时,共享迭代器将已经耗尽。


然而,在第二个示例中,当foriter上调用a时,会创建一个新的迭代器,每次 ;因此,创建了两个迭代器。这意味着每个循环都使用自己的迭代器,因此第二个循环不使用穷尽的迭代器。



换句话说,判断的方法是考虑是否每次使用都创建一个新的迭代器,还是多次使用一个旧的迭代器。