代码之家  ›  专栏  ›  技术社区  ›  minou

python:使用f.next()迭代时,将文件中的一行倒回

  •  9
  • minou  · 技术社区  · 15 年前

    当您使用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()得到的位置。

    我以前用过搜索/告诉 trick 在使用readline()迭代文件时倒回一行。在使用next()时,是否有方法倒回一行?

    3 回复  |  直到 13 年前
        1
  •  12
  •   lambacck    13 年前

    不,我会制作一个适配器,它主要转发所有调用,但在您发送时保留最后一行的副本 next 然后让您调用另一个方法,使该行再次弹出。

    实际上,我将使适配器成为一个可以包装任何iterable的适配器,而不是包装文件的适配器,因为听起来它在其他上下文中通常很有用。

    亚历克斯建议使用 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()
    

    这不会太难扩展到允许您以一个以上的值进行备份的内容中。

        2
  •  5
  •   Alex Martelli    15 年前

    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):
        ...
    
        3
  •  1
  •   Lesmana    14 年前

    python的文件迭代器做了大量的缓冲处理,从而使文件中的位置远远领先于迭代。如果你想用 file.tell() 你必须用“老办法”来做:

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