迭代器可以在Python中重置吗?

我可以重置Python中的迭代器/生成器吗? 我正在使用DictReader,并希望将其重置(从csv模块)到文件的开始。

我看到许多提示itertools.tee的答案,但这忽略了文档中的一个重要警告:

这个itertool可能需要大量的辅助存储(取决于需要存储多less临时数据)。 通常,如果一个迭代器在另一个迭代器启动之前使用大部分或全部数据,则使用list()而不是tee()会更快。

基本上, tee是为那些两个(或更多)一个迭代器的克隆在相互“不同步”的情况下devise的,而不是太多 – 而是在相同的“附近”(几个项目在彼此后面或前面)。 不适合OP的“从头再做”的问题。

另一方面, L = list(DictReader(...))是完全合适的,只要列表中的logging可以很好地适应记忆。 一个新的“迭代器从一开始”(非常轻量级和低开销)可以在任何时候使用iter(L) ,并部分或全部使用,而不会影响新的或现有的; 其他访问模式也很容易获得。

正如几个答案正确地表示,在csv的具体情况下,你也可以.seek(0)底层的文件对象(一个相当特殊的情况)。 我不确定这是logging和保证,虽然它目前的工作; 这可能是值得考虑的只有真正的巨大的csv文件,其中list我推荐作为一般的方法将有太大的内存占用。

如果您有一个名为“blah.csv”的csv文件,看起来像

 a,b,c,d 1,2,3,4 2,3,4,5 3,4,5,6 

你知道你可以打开文件阅读,并创build一个DictReader

 blah = open('blah.csv', 'r') reader= csv.DictReader(blah) 

然后,你将能够得到下一行reader.next() ,它应该输出

 {'a':1,'b':2,'c':3,'d':4} 

再次使用它会产生

 {'a':2,'b':3,'c':4,'d':5} 

然而,在这一点上,如果你使用blah.seek(0) ,下一次你调用reader.next()你会得到

 {'a':1,'b':2,'c':3,'d':4} 

再次。

这似乎是你正在寻找的function。 我确信有一些与这种方法相关的技巧,但我不知道。 @Brianbuild议简单地创build另一个DictReader。 如果你是第一个阅读器是通过阅读文件的一半,这是行不通的,因为你的新阅读器将在文件中的任何位置有意想不到的键和值。

不。Python的迭代器协议非常简单,只提供一个方法( .next()__next__() ),并且通常没有方法来重置迭代器。

常见的模式是改为使用相同的过程再次创build一个新的迭代器。

如果你想“保存”一个迭代器,以便你可以回到它的开始,你也可以使用itertools.tee

上面的Alex Martelli和Wilduck提倡使用.seek(0)存在一个错误,即下一次调用.next()会以{key1:key1,key2:key2的forms为您提供一个标题行的字典,…}。 解决方法是通过调用reader.next()来关注file.seek(0)以摆脱标题行。

所以你的代码看起来像这样:

 f_in = open('myfile.csv','r') reader = csv.DictReader(f_in) for record in reader: if some_condition: # reset reader to first row of data on 2nd line of file f_in.seek(0) reader.next() continue do_something(record) 

是的 ,如果你使用numpy.nditer构build你的迭代器。

 >>> lst = [1,2,3,4,5] >>> itr = numpy.nditer([lst]) >>> itr.next() 1 >>> itr.next() 2 >>> itr.finished False >>> itr.reset() >>> itr.next() 1 

虽然没有迭代器重置,Python 2.6(及更高版本)中的“itertools”模块有一些可以帮助的工具。 其中之一就是可以创build迭代器的多个副本的“tee”,并caching前面运行的结果,以便在副本上使用这些结果。 我会斩断你的目的:

 >>> def printiter(n): ... for i in xrange(n): ... print "iterating value %d" % i ... yield i >>> from itertools import tee >>> a, b = tee(printiter(5), 2) >>> list(a) iterating value 0 iterating value 1 iterating value 2 iterating value 3 iterating value 4 [0, 1, 2, 3, 4] >>> list(b) [0, 1, 2, 3, 4] 

这可能与原始问题是正交的,但是可以将迭代器封装在返回迭代器的函数中。

 def get_iter(): return iterator 

重置迭代器只需再次调用函数。 如果函数不带参数时,这当然是微不足道的。

在函数需要一些参数的情况下,使用functools.partial创build一个可以传递的闭包,而不是原始的迭代器。

 def get_iter(arg1, arg2): return iterator from functools import partial iter_clos = partial(get_iter, a1, a2) 

这似乎避免了tee(n个副本)或列表(1个副本)需要做的caching

只有基础types提供了这样的机制(例如fp.seek(0) )。

对于DictReader:

 f = open(filename, "rb") d = csv.DictReader(f, delimiter=",") f.seek(0) d.__init__(f, delimiter=",") 

对于DictWriter:

 f = open(filename, "rb+") d = csv.DictWriter(f, fieldnames=fields, delimiter=",") f.seek(0) f.truncate(0) d.__init__(f, fieldnames=fields, delimiter=",") d.writeheader() f.flush() 

list(generator())返回一个生成器的所有剩余值,如果没有循环,它将有效地重置它。