Python에서 반복기 / 생성기를 재설정 할 수 있습니까? DictReader를 사용 중이며 파일 시작 부분으로 재설정하고 싶습니다.
답변
itertools.tee 제안하는 많은 답변이 있지만 문서에서 중요한 경고 하나를 무시하고 있습니다.
이 itertool에는 상당한 보조 기억 장치가 필요할 수 있습니다 (저장해야하는 임시 데이터의 양에 따라 다름). 일반적으로 한 반복자가 다른 반복기가 시작되기 전에 대부분 또는 모든 데이터를 사용
list()
하는 경우tee()
.
기본적으로, tee
서로 “동기 벗어나 려”동시에 두 개 (또는 그 이상)의 하나 반복자의 클론, 그렇게하지 않는 상황을 위해 설계되었습니다 많은에 의해 오히려 그들은 같은 “근처”에서 말하는 (A – 서로 뒤 또는 앞의 몇 가지 항목). OP의 “처음부터 다시 실행”문제에 적합하지 않습니다.
L = list(DictReader(...))
반면에 딕셔너리 목록이 메모리에 편안하게 맞을 수있는 한 완벽하게 적합합니다. 새로운 “처음부터 반복자”(매우 가볍고 오버 헤드가 적음)는를 사용하여 언제든지 만들 수 있으며 iter(L)
신규 또는 기존 항목에 영향을주지 않고 부분적으로 또는 전체적으로 사용할 수 있습니다. 다른 액세스 패턴도 쉽게 사용할 수 있습니다.
여러 답변을 바르게 언급으로, 특정의 경우에 csv
할 수도 있습니다 .seek(0)
기본 파일 오브젝트 (다소 특별한 경우). 나는 그것이 현재 작동하고 있지만 그것이 문서화되고 보장되는지 확실하지 않습니다. list
일반적인 접근 방식이 너무 큰 메모리 풋 프린트를 가질 것이기 때문에 나는 정말 거대한 csv 파일에 대해서만 고려할 가치가있을 것입니다 .
답변
‘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의 반복기 프로토콜은 매우 간단하며 하나의 단일 메서드 ( .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 복사본)이 수행해야하는 캐싱을 피하는 것 같습니다.
답변
작은 파일의 경우 more_itertools.seekable
재설정 반복을 제공하는 타사 도구를 사용할 수 있습니다 .
데모
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
는 seekable
객체 (1)와 고급 (2)으로 래핑됩니다 . 이 seek()
메서드는 반복기를 0 번째 위치 (3)로 재설정 / 되감기하는 데 사용됩니다.
참고 : 메모리 소비는 반복에 따라 증가하므로 문서에 표시된 대로이 도구를 대용량 파일에 적용하는 데주의 하십시오 .