Можно ли сбросить итераторы в Python?



можно ли сбросить итератор / генератор в Python? Я использую диктофон и хотел бы сбросить его (из модуля csv) в начало файла.

688   12  

12 ответов:

Я вижу много ответов, предлагая itertools.ти, но это игнорирует одно важное предупреждение в документации к ней:

этот itertool может потребовать значительного вспомогательной памяти (в зависимости от много временных данных должно быть хранящийся.) В общем, если один итератор использует большинство или все данные перед запускается другой итератор, он быстрее использовать list() вместо tee().

по сути, tee предназначен для тех, ситуация, когда два (или более) клона одного итератора, "выходя из синхронизации" друг с другом, не делают этого много -- а, говорят, в той же "близости" (несколько пунктов позади или впереди друг друга). Не подходит для проблемы ОП "повторить с самого начала".

L = list(DictReader(...)) С другой стороны идеально подходит, до тех пор, как список диктов может удобно поместиться в памяти. Новый "итератор с самого начала" (очень легкий и с низкими накладными расходами) может быть сделан по адресу в любое время с iter(L), и использованный частично или в целом без влияния новых или существующих одних; другие картины доступа также легко доступны.

как справедливо отметили несколько ответов, в конкретном случае csv вы можете .seek(0) базовый файловый объект (довольно частный случай). Я не уверен, что это задокументировано и гарантировано, хотя в настоящее время это работает; вероятно, стоит рассмотреть только для действительно огромных файлов csv, в которых list Я рекомендую как общий подход будет иметь слишком большой объем памяти.

если у вас есть csv-файл с именем 'blah.csv ' это выглядит как

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

вы знаете, что вы можете открыть файл для чтения и создания 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}

снова.

это, кажется, функциональность, которую вы ищете. Я уверен, что есть некоторые трюки, связанные с этим подходом, которые я не знаю, однако. @Брайан предложил просто создать еще один диктофон. Это не будет работать, если вы первый читатель на полпути через чтение файла, как ваш новый читатель будет иметь неожиданные ключи и значения из любого места в файле.

нет. Протокол итератора Python очень прост и предоставляет только один метод (.next() или __next__()), и нет метода для сброса итератора в целом.

общий шаблон заключается в том, чтобы вместо этого создать новый итератор, используя ту же процедуру снова.

Если вы хотите "сохранить" итератор, чтобы вы могли вернуться к его началу, вы также можете разветвить итератор с помощью itertools.tee

есть ошибка в использовании .ищите(0), как это отстаивали Алекс Мартелли и Уайлдак выше, а именно, что следующий вызов .далее () даст вам словарь вашей строки заголовка в виде {key1:key1, key2:key2, ...}. Работа вокруг, чтобы следовать файл.искать(0) с помощью вызова reader.следующий() чтобы избавиться от строки заголовка.

Так что ваш код будет выглядеть примерно так:

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

хотя нет сброса итератора, модуль "itertools" из python 2.6 (и более поздних версий) имеет некоторые утилиты, которые могут помочь там. Один из них-это "тройник", который может создавать несколько копий итератора и кэшировать результаты одного из них, чтобы эти результаты использовались на копиях. Я разделю ваши цели:

>>> 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.частично, чтобы создать закрытие, которое может быть передано вместо оригинала итератор.

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

это, кажется, чтобы избежать кэширования, что tee (n копий) или список (1 копия) нужно будет сделать

для небольших файлов, вы можете использовать more_itertools.seekable - сторонний инструмент, который предлагает сброс iterables.

демо

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'}

здесь a DictReader обернут в

только если базовый тип обеспечивает механизм для этого (например,fp.seek(0)).

Для DictReader:

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

f.seek(0)
d.__init__(f, delimiter=",")

Для Диктатора:

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()) возвращает все оставшиеся значения для генератора и эффективно сбрасывает его, если он не зациклен.

Comments

    Ничего не найдено.