Question

I'm writing a script that logs errors from another program and restarts the program where it left off when it encounters an error. For whatever reasons, the developers of this program didn't feel it necessary to put this functionality into their program by default.

Anyways, the program takes an input file, parses it, and creates an output file. The input file is in a specific format:

UI - 26474845
TI - the title (can be any number of lines)
AB - the abstract (can also be any number of lines)

When the program throws an error, it gives you the reference information you need to track the error - namely, the UI, which section (title or abstract), and the line number relative to the beginning of the title or abstract. I want to log the offending sentences from the input file with a function that takes the reference number and the file, finds the sentence, and logs it. The best way I could think of doing it involves moving forward through the file a specific number of times (namely, n times, where n is the line number relative to the beginning of the seciton). The way that seemed to make sense to do this is:

i = 1
while i <= lineNumber:
    print original.readline()
    i += 1

I don't see how this would make me lose data, but Python thinks it would, and says ValueError: Mixing iteration and read methods would lose data. Does anyone know how to do this properly?

Was it helpful?

Solution

You get the ValueError because your code probably has for line in original: in addition to original.readline(). An easy solution which fixes the problem without making your program slower or consume more memory is changing

for line in original:
    ...

to

while True:
    line = original.readline()
    if not line: break
    ...

OTHER TIPS

Use for and enumerate.

Example:

for line_num, line in enumerate(file):
    if line_num < cut_off:
        print line

NOTE: This assumes you are already cleaning up your file handles, etc.

Also, the takewhile function could prove useful if you prefer a more functional flavor.

Assuming you need only one line, this could be of help

import itertools

def getline(fobj, line_no):
    "Return a (1-based) line from a file object"
    return itertools.islice(fobj, line_no-1, line_no).next() # 1-based!

>>> print getline(open("/etc/passwd", "r"), 4)
'adm:x:3:4:adm:/var/adm:/bin/false\n'

You might want to catch StopIteration errors (if the file has less lines).

Here's a version without the ugly while True pattern and without other modules:

for line in iter(original.readline, ''):
    if …:   # to the beginning of the title or abstract
        for i in range(lineNumber):
            print original.readline(),
        break
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top