본문 바로가기

개발하자

Python: f.next()로 반복할 때 파일에서 한 줄을 되감습니다

반응형

Python: f.next()로 반복할 때 파일에서 한 줄을 되감습니다

f.next():로 파일을 반복할 때 파이썬의 f.tell이 내가 예상했던 것처럼 작동하지 않는다:

>>> f=open(".bash_profile", "r")
>>> f.tell()
0
>>> f.next()
"alias rm='rm -i'\n"
>>> f.tell()
397
>>> f.next()
"alias cp='cp -i'\n"
>>> f.tell()
397
>>> f.next()
"alias mv='mv -i'\n"
>>> f.tell()
397

다음()으로 방금 얻은 것의 위치보다는 버퍼의 위치를 제공하는 것처럼 보입니다.

나는 이전에 읽기 줄()로 파일을 반복할 때 한 줄을 되감기 위해 검색/말하기를 사용한 적이 있다. next()를 사용할 때 한 줄을 되감는 방법이 있나요?




가장 덜 나쁜 접근 방식일 것입니다. 파일에서 반복적으로 수행되는 버퍼링을 "제거"할 수 없습니다(성능 효과가 끔찍할 수도 있습니다). 따라서 한 번은 다른 한 번보다 "한 발짝 뒤로" 두 번만 유지하는 것이 가장 좋은 해결책인 것 같습니다.

import itertools as it

with open('a.txt') as f:
  f1, f2 = it.tee(f)
  f2 = it.chain([None], f2)
  for thisline, prevline in it.izip(f1, f2):
    ...



Python의 파일 반복기는 많은 버퍼링을 수행하므로 파일의 위치를 반복보다 훨씬 앞서 진행할 수 있습니다. 사용하려면 "기존 방식"을 사용해야 합니다:

with open(filename) as fileob:
  line = fileob.readline()
  while line:
    print fileob.tell()
    line = fileob.readline()



아니요. 저는 모든 통화를 전송하는 어댑터를 만들지만, 당신이 전송할 때 마지막 줄의 복사본을 보관하고 있다가 그 줄이 다시 튀어나오도록 다른 방법을 호출할 수 있게 해줄 것입니다.

나는 실제로 어댑터를 파일용 래퍼 대신 임의의 반복 가능한 랩핑이 가능한 어댑터로 만들 것이다. 왜냐하면 그것은 다른 맥락에서 자주 유용할 것처럼 들리기 때문이다.

어댑터를 사용하자는 Alex의 제안도 효과가 있지만, 일반적으로 이 경우를 처리하기 위해 당신만의 반복기 어댑터를 작성하는 것이 더 깨끗할 것 같습니다.

다음은 예입니다:

class rewindable_iterator(object):
    not_started = object()

    def __init__(self, iterator):
        self._iter = iter(iterator)
        self._use_save = False
        self._save = self.not_started

    def __iter__(self):
        return self

    def next(self):
        if self._use_save:
            self._use_save = False
        else:
            self._save = self._iter.next()
        return self._save

    def backup(self):
        if self._use_save:
            raise RuntimeError("Tried to backup more than one step.")
        elif self._save is self.not_started:
            raise RuntimeError("Can't backup past the beginning.")
        self._use_save = True


fiter = rewindable_iterator(file('file.txt', 'r'))
for line in fiter:
    result = process_line(line)
    if result is DoOver:
        fiter.backup()

하나 이상의 값으로 백업할 수 있는 기능으로 확장하는 것은 그리 어렵지 않습니다.


반응형