TMWP
TMWP

Reputation: 1625

Python file object allows you to close a file that is already closed

Creating code in 2.7 (for a Python class I am taking) and cross-testing it in 3.x (for me). This code is not required. I decided to build objects that might be useful for the future instead of simply answering the original question directly.

Since 3.x has no file object to inherit, my object uses file instances within it instead of inheriting from it directly. During testing of the code which follows, I encountered an oddity. I can close a file and then close it again and this does not trigger any kind of error. To sanity checking this code is being built right, two questions about this: * why can I close the same file twice * the way I have written this, when I close the file, am I really closing it and freeing up the memory the file object is taking up?

Here is the code:

class FileData(object):
    def __init__(self, xfilename, xmode):
        self.filename = xfilename
        self.mode = xmode
        self.f = open(xfilename, 'r')

    def getAllFileData(self):
        self.lines = f.readlines()
        self.f.close()

    def getLineFromFile(self):
        if f.closed:
            self.f = open(xfilename, 'r')    
        self.f.readline()

    def fileHead(self, numRows):
        if self.f.closed:
            self.f = open(xfilename, 'r')

        for i in range(numRows):
            print(self.f.readline())
        self.f.close()

Then I ran these test lines and accidentally re-ran the line to close the file multiple times. To make sure I wasn't missing something, I later organized these lines in a Jupyter cell and ran them together.

chatLog = FileData("script/record.txt", "r")
chatLog.fileHead(15)

chatLog.f.close()
chatLog.f.close()

Note that fileHead() also closes the file when done, so really above code should have tried to close the same file 3 times.

Why no error? And is this closing the file the way I think it is? Learning the language so any input would be appreciated.

Upvotes: 4

Views: 4288

Answers (2)

shad0w_wa1k3r
shad0w_wa1k3r

Reputation: 13373

Because using .close() repeatedly is okay. Internally, it might be checking .closed to be True then do nothing, else actually close the file.

Upvotes: 2

Jean-François Fabre
Jean-François Fabre

Reputation: 140287

f.close() won't do anything if the file is already closed as you noticed yourself.

You could protect against it but seeing how complex it is I wouldn't advise to do it:

import _io

def override_close(f):
    if f.closed:
        raise IOError("already closed error")
    else:
        _io.TextIOWrapper.close(f)

f = open("foo.c")
f.close = lambda : override_close(f)

print("closing")
f.close()
print("protected")
f.close()   # raises IOError

I have overridden the close method for the f object so it checks against already closed file and raises an exception.

For your example, the best way would be to hide f (and other data) from the outside by making them not directly invisible from the outside:

self.__f = open(...)

so callers cannot mess (easily :)) with your file handle anymore.

Upvotes: 2

Related Questions