Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中可以重置迭代器吗?_Python_Iterator_Generator - Fatal编程技术网

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

在Python中可以重置迭代器吗?,python,iterator,generator,Python,Iterator,Generator,我可以在Python中重置迭代器/生成器吗?我正在使用DictReader,希望将其重置为文件的开头。仅当底层类型提供了执行此操作的机制时(例如fp.seek(0))。否。Python的迭代器协议非常简单,只提供了一个方法(.next()或\uuuuu next()),通常没有重置迭代器的方法 常见的模式是再次使用相同的过程创建一个新的迭代器 如果您想“保存”迭代器,以便可以返回到它的开头,如果您有一个名为“blah.csv”的csv文件 a,b,c,d 1,2,3,4 2,3,4,5 3,4,

我可以在Python中重置迭代器/生成器吗?我正在使用DictReader,希望将其重置为文件的开头。

仅当底层类型提供了执行此操作的机制时(例如
fp.seek(0)
)。

否。Python的迭代器协议非常简单,只提供了一个方法(
.next()
\uuuuu next()
),通常没有重置迭代器的方法

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


如果您想“保存”迭代器,以便可以返回到它的开头,如果您有一个名为“blah.csv”的csv文件

a,b,c,d
1,2,3,4
2,3,4,5
3,4,5,6
您知道可以打开文件进行读取,并使用

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}
再说一遍


这似乎是您正在寻找的功能。我确信有一些技巧与这种方法相关,但我不知道@布赖恩建议只创建另一个听写器。如果您的第一个读卡器正在读取文件的一半,那么这将不起作用,因为您的新读卡器将从文件中的任何位置获得意外的键和值。

虽然没有迭代器重置,但python 2.6(及更高版本)中的“itertools”模块有一些实用程序可以帮助您实现这一点。 其中一个是“tee”,它可以创建迭代器的多个副本,并缓存前面运行的迭代器的结果,以便在副本上使用这些结果。我将为您服务:

>>> 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]

我看到很多答案都在暗示,但这忽略了文档中的一个关键警告:

此itertool可能需要大量的 辅助存储器(取决于使用方式 需要更新许多临时数据 存储的)。通常,如果一个迭代器 使用之前的大部分或所有数据 另一个迭代器启动,速度更快 使用
list()
代替
tee()

基本上,
tee
是为一个迭代器的两个(或多个)克隆设计的,当它们彼此“不同步”时,它们不会这样做——相反,它们说的是在同一个“附近”(彼此后面或前面的几个项目)。不适用于OP的“从头重做”问题

另一方面,
L=list(DictReader(…)
是非常合适的,只要dicts列表可以轻松地放入内存中。新的“从头开始的迭代器”(非常轻量级和低开销)可以随时使用
iter(L)
,并在不影响新的或现有迭代器的情况下部分或全部使用;其他访问模式也很容易获得


正如一些答案正确地指出的那样,在
csv
的特定情况下,您还可以
.seek(0)
底层文件对象(一种非常特殊的情况)。我不确定是否有文件记录和保证,尽管它目前确实有效;只有真正巨大的csv文件才值得考虑,我推荐使用
列表,因为一般的方法会占用太大的内存。

使用
.seek(0)
,这是Alex Martelli和Wilduck所提倡的,即下一次调用
.next()
将以
{key1:key1,key2:key2,…}
的形式提供标题行的字典。解决方法是在
file.seek(0)
之后调用
reader.next()
以除去标题行

因此,您的代码如下所示:

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
构建迭代器

>>> lst = [1,2,3,4,5]
>>> itr = numpy.nditer([lst])
>>> itr.next()
1
>>> itr.next()
2
>>> itr.finished
False
>>> itr.reset()
>>> itr.next()
1
对于听写器:

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()

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

def get_iter():
    return iterator
def get_iter(arg1, arg2):
   return iterator
from functools import partial
iter_clos = partial(get_iter, a1, a2)
要重置迭代器,只需再次调用该函数。 如果函数没有参数,那么这当然是微不足道的

如果函数需要一些参数,请使用functools.partial创建可以传递的闭包,而不是原始迭代器

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

<>这似乎避免了TE(n个副本)或列表(1个拷贝)需要做的缓存:

< p> <代码>列表(Guangor())<代码>:返回一个生成器的所有剩余值,并在没有循环的情况下有效地重置它。

对于小文件,可以考虑使用第三方提供重置迭代的工具。

演示

import csv

import more_itertools as mit


filename = "data/iris.csv"
with open(filename, "r") as f:
    reader = csv.DictReader(f)
    iterable = mit.seekable(reader)                    # 1
    print(next(iterable))                              # 2
    print(next(iterable))
    print(next(iterable))

    print("\nReset iterable\n--------------")
    iterable.seek(0)                                   # 3
    print(next(iterable))
    print(next(iterable))
    print(next(iterable))
输出

{'Sepal width': '3.5', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '5.1', 'Species': 'Iris-setosa'}
{'Sepal width': '3', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '4.9', 'Species': 'Iris-setosa'}
{'Sepal width': '3.2', 'Petal width': '0.2', 'Petal length': '1.3', 'Sepal length': '4.7', 'Species': 'Iris-setosa'}

Reset iterable
--------------
{'Sepal width': '3.5', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '5.1', 'Species': 'Iris-setosa'}
{'Sepal width': '3', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '4.9', 'Species': 'Iris-setosa'}
{'Sepal width': '3.2', 'Petal width': '0.2', 'Petal length': '1.3', 'Sepal length': '4.7', 'Species': 'Iris-setosa'}
这里,
DictReader
被包装在可查看的对象(1)和高级对象(2)中。
seek()
方法用于将迭代器重置/回放到第0个位置(3)

注意:内存消耗随着迭代的增加而增加,所以要小心将此工具应用于大文件,因为这是一个问题。

我以前也有过同样的问题。在分析了我的代码之后,我意识到尝试在循环内部重置迭代器会稍微增加时间复杂度,这也会使代码有点难看

解决方案 打开文件并将行保存到内存中的变量中

# initialize list of rows
rows = []

# open the file and temporarily name it as 'my_file'
with open('myfile.csv', 'rb') as my_file:

    # set up the reader using the opened file
    myfilereader = csv.DictReader(my_file)

    # loop through each row of the reader
    for row in myfilereader:
        # add the row to the list of rows
        rows.append(row)

现在,您可以在范围内的任意位置循环行,而无需处理迭代器。

一个可能的选项是使用,它将允许您无限期地迭代,而无需任何技巧,如
。seek(0)

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

我也遇到了同样的问题——虽然我喜欢
tee()
解决方案,但我不知道我的文件会有多大,而且关于先消耗一个文件再消耗另一个文件的内存警告也让我无法采用这种方法

相反,我正在使用
iter()
语句创建一对迭代器,并在切换到第二个迭代器进行最终运行之前,使用第一个迭代器进行初始运行

所以,在t
from copy import deepcopy
iterator = your_iterator

# Start iteration
iterator_altered = deepcopy(iterator)
for _ in range(2):
    a = next(iter(iterator_altered))

# Your iterator is still unaltered.