programing

파이썬에서 반복기를 재설정할 수 있습니까?

bestprogram 2023. 6. 21. 22:51

파이썬에서 반복기를 재설정할 수 있습니까?

파이썬에서 반복기/생성기를 재설정할 수 있습니까?DictReader를 사용하고 있으며 파일의 시작 부분으로 재설정하고 싶습니다.

저는 itertools.tee를 제안하는 많은 답변을 보았지만, 그것은 문서에서 그것에 대한 중요한 경고 하나를 무시하는 것입니다.

이iter 도구는 저장해야 하는 임시 데이터의 양에 따라 상당한 보조 스토리지가 필요할 수 있습니다.일반적으로 한 반복기가 다른 반복기를 시작하기 전에 데이터의 대부분 또는 전부를 사용하는 경우 사용하는 것이 더 빠릅니다.list()tee().

기적으로본,tee하나의 반복기의 두 개 이상의 복제본이 서로 "동기화되지 않음" 상태에서 서로 "동기화되지 않음" 상태를 유지하는 상황에 맞게 설계되었습니다. 오히려 동일한 "동기화" 상태(서로 뒤에 있거나 앞에 있는 항목)로 말합니다.OP의 "시작부터 다시 하기" 문제에 적합하지 않습니다.

L = list(DictReader(...))반면에 딕트 목록이 메모리에 편안하게 들어갈 수 있는 한 완벽하게 적합합니다.새로운 "처음부터 반복기"(매우 가볍고 오버헤드가 낮은)는 언제든지 만들 수 있습니다.iter(L)또한 새로운 액세스 패턴이나 기존 액세스 패턴에 영향을 주지 않고 일부 또는 전체적으로 사용할 수 있습니다.

몇몇 대답이 옳게 언급했듯이, 의 구체적인 경우에.csv당신은 또한 할 수 있습니다..seek(0)기본 파일 개체(특별한 경우)입니다.보장되어 하고 있습니다. 정말 큰 파일에 해 볼 입니다. 이 에서 "csv 파일"은 다음과 같습니다. 아마도 정말 거대한 CSV 파일에 대해서만 고려할 가치가 있을 것입니다.list일반적인 접근 방식은 메모리 설치 공간이 너무 크기 때문에 권장합니다.

이름이 'blah.csv'인 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}

다시.

이것이 당신이 찾고 있는 기능인 것 같습니다.이 접근 방식과 관련하여 제가 알지 못하는 몇 가지 속임수가 있을 것이라고 확신합니다.@Brian은 단순히 다른 DictReader를 만들자고 제안했습니다.첫 번째 판독기가 파일을 읽는 도중이면 새 판독기가 파일의 어느 위치에서든지 예상치 못한 키와 값을 갖게 되므로 이 기능은 작동하지 않습니다.

Python의 하며, 단 합니다("Python", "Python", "Python")..next()또는__next__() 및 일반적으로 반복기를 재설정하는 방법이 없습니다.

일반적인 패턴은 동일한 절차를 다시 사용하여 새 반복기를 만드는 것입니다.

반복기를 "저장"하여 처음으로 돌아갈 수 있도록 하려면 다음을 사용하여 반복기를 포크할 수도 있습니다.itertools.tee

, 사용할 경우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

을 사용하는 데 문제가 있습니다..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)

이것은 아마도 원래 질문과 직교하지만, 반복기를 반환하는 함수로 반복기를 감쌀 수 있습니다.

def get_iter():
    return iterator

반복기를 재설정하려면 함수를 다시 호출하십시오.이는 해당 함수가 인수를 사용하지 않는 함수인 경우 당연히 사소한 것입니다.

함수에 일부 인수가 필요한 경우 functools.partial을 사용하여 원래 반복자 대신 전달할 수 있는 폐쇄를 만듭니다.

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

이렇게 하면 티(n개) 또는 목록(1개)이 수행해야 하는 캐싱을 피할 수 있습니다.

작은 파일의 경우, 재설정 반복 가능한 타사 도구를 사용하는 것을 고려할 수 있습니다.

데모

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여▁a▁in▁wrapped다▁is니습있에 싸여 있습니다.seekable개체(1) 및 고급(2).seek()메소드는 반복기를 0번째 위치(3)로 재설정/재설정하는 데 사용됩니다.

참고: 메모리 사용량은 반복됨에 따라 증가하므로 설명서에 나와 있는 대로 이 도구를 대용량 파일에 적용하는 것을 주의하십시오.

한 가지 가능한 옵션은 다음과 같은 속임수 없이 무한 반복할 수 있는 를 사용하는 것입니다..seek(0).

iterDic = itertools.cycle(csv.DictReader(open('file.csv')))

반복기 재설정은 없지만 python 2.6 이상의 "itterools" 모듈에는 이를 지원하는 몇 가지 유틸리티가 있습니다.그 중 하나는 "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]

'iter()' 호출 중 마지막 반복 시 새로 생성된 반복기 반환

class ResetIter: 
  def __init__(self, num):
    self.num = num
    self.i = -1

  def __iter__(self):
    if self.i == self.num-1: # here, return the new object
      return self.__class__(self.num) 
    return self

  def __next__(self):
    if self.i == self.num-1:
      raise StopIteration

    if self.i <= self.num-1:
      self.i += 1
      return self.i


reset_iter = ResetRange(10)
for i in reset_iter:
  print(i, end=' ')
print()

for i in reset_iter:
  print(i, end=' ')
print()

for i in reset_iter:
  print(i, end=' ')

출력:

0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 

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())생성기의 나머지 값을 모두 반환하고 루프되지 않은 경우 이 값을 효과적으로 재설정합니다.

문제

저도 전에 같은 문제를 겪은 적이 있습니다.제 코드를 분석한 후, 저는 루프 내부의 반복기를 재설정하려고 시도하면 시간 복잡성이 약간 증가하고 코드를 약간 추하게 만든다는 것을 깨달았습니다.

해결책

파일을 열고 행을 메모리의 변수에 저장합니다.

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

이제 반복기를 사용하지 않고 범위 내의 모든 위치에서 행을 반복할 수 있습니다.

나는 이 같은 문제에 도달할 것입니다 - 내가 좋아하는 동안.tee()솔루션, 파일 크기가 어느 정도가 될 것인지 알 수 없으며, 다른 파일보다 먼저 하나를 사용해야 한다는 메모리 경고로 인해 이 방법을 채택하는 것을 미루고 있습니다.

대신, 나는 한 쌍의 반복기를 만들고 있습니다.iter()첫 번째 실행을 위해 첫 번째 실행을 사용하고 마지막 실행을 위해 두 번째 실행으로 전환합니다.

따라서 딕트 리더의 경우 리더가 다음을 사용하여 정의된 경우:

d = csv.DictReader(f, delimiter=",")

다음을 사용하여 이 "사양"에서 한 쌍의 반복기를 만들 수 있습니다.

d1, d2 = iter(d), iter(d)

그런 다음 1차 패스 코드를 실행할 수 있습니다.d1두 번째 반복자가 있다는 것을 알고도 안전합니다.d2동일한 루트 사양에서 정의되었습니다.

저는 이것을 철저하게 테스트하지는 않았지만, 더미 데이터에서 작동하는 것 같습니다.

이 그렇게에만 ( 기유형이예위를제을경해공우당만다니됩에는하즘니커이한메본예(▁for▁provides:▁only다해니▁the당▁mechanism됩▁a:fp.seek(0)).

가능한 가장 간단한 솔루션: 딥 카피 사용

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. 

저는 이것이 간단한 접근법이라고 생각합니다.

언급URL : https://stackoverflow.com/questions/3266180/can-iterators-be-reset-in-python