生成器之类的可迭代项只能被迭代一次:
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
如果该参数可以重复多次,则无需保存其他副本。
答案 0 :(得分:4)
示例之间的主要区别在于,在生成器示例中,在循环发生之前创建了一个迭代器,然后将该相同的迭代器使用了两次。但是,在清单示例中,每个循环都使用一个新的迭代器。
在第一个示例中,生成器本身就是迭代器。当你做
a = f()
对f
的调用将创建一个生成器(它是一个迭代器)。当您将a
赋予for
循环时,它们会在iter
上调用a
,它会返回自身。简短的MCVE轻松显示了这一点:
l = [1]
i = iter(l)
j = iter(i)
print(i is j) # Prints True
两个循环都使用一个迭代器。这意味着到第二个循环开始时,共享迭代器将已经耗尽。
然而,在第二个示例中,当for
在iter
上调用a
时,会创建一个新的迭代器,每次 ;因此,创建了两个迭代器。这意味着每个循环都使用自己的迭代器,因此第二个循环不使用穷尽的迭代器。
换句话说,判断的方法是考虑是否每次使用都创建一个新的迭代器,还是多次使用一个旧的迭代器。