10

f.next() を使用してファイルを反復処理すると、Python の 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() で取得したばかりの位置ではなく、バッファの位置が得られるようです。

readline() を使用してファイルを反復処理するときに、seek/tellトリックを使用して 1 行巻き戻したことがあります。next() を使用するときに 1 行巻き戻す方法はありますか?

4

3 に答える 3

12

いいえ。すべての呼び出しを大部分転送するアダプターを作成しますが、転送時に最後の行のコピーを保持しnext、別のメソッドを呼び出してその行を再度ポップアウトさせます。

実際には、アダプターをファイルのラッパーではなく、反復可能なものをラップできるアダプターにします。これは、他のコンテキストで頻繁に役立つように聞こえるためです。

アダプターを使用するという Alex の提案itertools.teeも機能しますが、一般的にこのケースを処理するために独自の反復子アダプターを作成する方がクリーンになると思います。

以下に例を示します。

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

これを拡張して、複数の値でバックアップできるようにすることはそれほど難しくありません。

于 2010-08-21T21:46:56.147 に答える
5

itertools.teeは、おそらく最も悪いアプローチです。ファイルを反復処理することによって行われるバッファリングを「打ち負かす」ことはできません (パフォーマンスへの影響はひどいでしょう)。もう一方の一歩を踏み出すことが、私には最も健全な解決策のように思えます。

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):
    ...
于 2010-08-21T21:45:02.747 に答える
1

Python のファイル反復子は多くのバッファリングを行うため、ファイル内の位置を反復よりはるかに先に進めます。使用したい場合file.tell()は、「古い方法」で行う必要があります。

with open(filename) as fileob:
  line = fileob.readline()
  while line:
    print fileob.tell()
    line = fileob.readline()
于 2010-08-21T21:46:35.310 に答える