with open(), how can I tell if I am at the last line of a file?

Viewed 103

I have:

with open(self.corpus_file) as infile:
    for line in infile:

How can I tell if line is the last line in infile?

This is with Python 3.6 if that matters.

5 Answers

Here's a simple way:

from itertools import tee

with open(self.corpus_file) as infile:
    infile, check = tee(infile)
    try:
        next(check)
    except StopIteration:
        # file is empty
    for line in infile:
        try:
            next(check)
        except StopIteration:
            # line is the last line

Another even simpler way if you don't have to stay in the loop:

with open(self.corpus_file) as infile:
    for line in infile:
        pass

# line is now the last line

File objects returned by open are iterators in Python, so you can look out for StopIteration while doing next to consume lines in a while loop:

with open(self.corpus_file) as f: 
    line = None 
    while True: 
        try: 
            line = next(f) 
        except StopIteration: 
            break 

Now line should contain the last line.

Generally you don't want to try to figure that out inside the loop, but rather, you'll know you've reached the end when the loop exits. If you want to do something special if you've reached the end (and might sometimes break out of the loop), you can add an else clause to the for:

with open(filename) as file:
    for line in file:
        if not do_stuff(line):
            break
    else: # got to the end without breaking
        do_something_special_with_last_line(line)

Using the fact that files are iterators, you can use the following generic recipe. It returns a status flag along with each line. The flag is True for the last element of the underlying iterator:

def is_last(iterator):
    prev = next(iterator)  # immediate StopIteration possible
    for item in iterator:
        yield False, prev
        prev = item
    yield True, prev

You would use it like

with open(...) as infile:
    for last, line in is_last(infile):
        ...

You could use a collections.deque like this:

from collections import deque


def read_file(filename):
    with open(filename) as infile:
        dq = deque([next(infile)], 1)
        for line in infile:
            yield dq[0]
            dq.append(line)

    # Last line of file.
    yield 'LAST LINE: ' + dq[0]


corpus_file = 'corpus_file.txt'

for line in read_file(corpus_file):
    print(line, end='')
Related