【问题标题】:How to tell if an iterable can be iterated only once?如何判断一个可迭代对象是否只能迭代一次?
【发布时间】:2020-01-03 03:18:23
【问题描述】:

像生成器这样的可迭代对象只能迭代一次:

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

如果我们可以判断一个可迭代对象是否只能迭代一次,我们可以使实现更加节省内存:

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

如果参数可以迭代多次,我们不需要保存额外的副本。

【问题讨论】:

  • 没有办法判断你是否只知道它是一个可迭代的,但是,所有的 迭代器 都应该只是一次传递。所以,iter(iterable) is iterable 是一个很好的指标,表明它是单通道
  • 你有这方面的文件吗?我觉得很奇怪,没有办法说出来。
  • 你怎么可能知道?您可以想要以任何方式实现可迭代。您可以阅读 Python 中的迭代器协议来搜索文档。但一般来说,所有正确实现的迭代器都是单程的(虽然这不是由语言强制执行的)。所有内置容器都可以迭代多次。
  • 是的,iterators 只是为了简单的通过。不过,我说的是iterable
  • @youkaichao:迭代器本身是可迭代的。例如it = iter([]); iter(it) is it。 (此外,“更节省内存”的实现是不正确的......而且也不是更节省内存。它不会在获取值后立即产生值,并且不适用于无限迭代。)跨度>

标签: python iterator iterable


【解决方案1】:

您的示例之间的主要区别在于,在生成器示例中,在循环发生之前创建了一个迭代器,然后使用了两次相同的迭代器。然而,在列表示例中,每个循环都使用了一个新的迭代器。


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

a = f()

f 的调用会创建一个生成器(它是一个迭代器)。当您将a 提供给for 循环时,它们会在a 上调用iter,这返回自身。一个简短的 MCVE 很容易说明这一点:

l = [1]
i = iter(l)

j = iter(i)

print(i is j)  # Prints True

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


然而,在第二个示例中,当fora 上调用iter 时,每次都会创建一个新的迭代器;所以创建了两个迭代器。这意味着每个循环都使用自己的迭代器,因此第二个循环没有使用耗尽的迭代器。



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

【讨论】:

  • 但是python开发者说不可能:github.com/python/cpython/pull/17783
  • @youkaichao 当我发布这个答案时,你没有发布cycle 部分,所以我解释了这个问题,因为你问为什么会有不同的行为。不,可能没有可靠的程序化方式来说明。
猜你喜欢
  • 2022-01-26
  • 2017-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-29
  • 2011-01-13
  • 1970-01-01
相关资源
最近更新 更多