Reputation: 1625
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
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
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