0

Let us say, we have the following code:

from sys import exit

def parseLine(l):
    if '#' not in l: 
        print 'Invalid expresseion'
        exit(1)
    return l


with open('somefile.txt') as f:
    for l in f:
        print parseLine(l)

(Note that this is a demo code. The actual program is much more complex.)

Now, how do I know if I have safely closed all the open files when I exit from the program? At this point I am just assuming that the files have been closed. Currently my programs are working OK, but I want them to be robust and free of problems related to files not closed properly.

3 Answers 3

7

One of the chief benefits of the with block with files is that it will automatically close the file, even if there's an exception.

https://docs.python.org/2/tutorial/inputoutput.html#methods-of-file-objects

0
3

It's already closing properly, since you're using a with statement when you open the file. That'll automatically close the file when control leaves the with statement, even if there's an exception. This is usually considered the best way to ensure files are closed when they should be.

If you don't use a with statement or close the file yourself, there are a few built-in safeties and a few pitfalls.

First, in CPython, the file object's destructor will close the file when it gets garbage-collected. However, that isn't guaranteed to happen in other Python implementations, and even in CPython, it isn't guaranteed to happen promptly.

Second, when your program exits, the operating system will close any files the program left open. This means if you accidentally do something that makes the program never close its files (perhaps you had to issue a kill -9 or something else that prevents cleanup code from running), you don't have to reboot the machine or perform filesystem repair to make the file usable again. Relying on this as your usual means of closing files would be inadvisable, though.

1

If you're using a with block, you essentially have your open call inside of a try block and the close in a finally block. See https://docs.python.org/2/tutorial/inputoutput.html for more information from the official docs.

Since calling exit() actually raises the SystemExit exception, all code within finally blocks will be run before the program completely exits. Since this is the case, and since you're using with open(...) blocks, the file will be closed with any uncaught exception.

Below is your code (runnable/debuggable/steppable at http://python.dbgr.cc/s)

from sys import exit

def parseLine(l):
    if '#' not in l: 
        print 'Invalid expresseion'
        exit(1)
    return l


with open('somefile.txt') as f:
    for l in f:
        print parseLine(l)

print("file is closed? %r" % f.closed)

Equivalent code without using the with open(...) block is shown below (runnable/debuggable at http://python.dbgr.cc/g):

from sys import exit

def parseLine(l):
    if '#' not in l: 
        print 'Invalid expresseion'
        exit(1)
    return l

try:
    f = open('somefile.txt')
    for l in f:
        print parseLine(l)
finally:
    print("Closing open file!")
    f.close()

print("file is closed? %r" % f.closed)

Not the answer you're looking for? Browse other questions tagged or ask your own question.