4

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.

3
  • funny I thought it would have crashed, but apparently it just does nothing. BTW I suggest that you protect your members using __ to make them invisible (hardly visible) from the outside so callers cannot mess with them. Commented Mar 22, 2017 at 14:26
  • Thanks for the suggestion. I can see you have a lot more experience with Python than me, but in class just this week, I asked if __function__ means private and my instructor insisted that it does not. That this syntax is for reserved functions like __str__ where we are over-writing something built into the language. My instructor is a physicist who learned Python for his work, but that doesn't mean he's infalible. Is he wrong? Does "__" mean private and I can use it that way to protect elements in my object? Commented Mar 22, 2017 at 14:33
  • Names that begin and end with double underscores are special, and normal scripts shouldn't create names like that. It's confusing to readers, and it could clash with existing special names, or ones added to Python in the future. Class attributes beginning with 1 or 2 underscores and ending with at most 1 underscore are conventionally used for "private" and "hidden" names, see the links to PEP-0008 I posted in this comment to Jean-François. Commented Mar 22, 2017 at 14:49

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

6 Comments

Leading single underscores are to indicate private attributes, leading double underscores invoke name-mangling, which should only be used to prevent name collisions with subclasses. Please see Method Names and Instance Variables and Designing for inheritance in PEP-0008.
This link was in another answer and should really be added to this one for completeness, but I don't have the rights to edit it. The other answer was more direct, this answer, is more complete and helped me even more, so I just accepted it. Here is the link. If you have time and are allowed to do so, suggest putting all 3 links from your comment in mine as references so when others use this post and other comments appear, they will still have these helpful links at their finger tips. Thanks so much for your answers. docs.python.org/2.7/library/stdtypes.html#file.close
@PM2Ring thanks. I tend to use __ but what you say makes sense. However, the simple underscore is a thin protection because some inexperienced user could still ignore that and use it (I tend to think of simple underscore as "protected" members, implicitly discouraged of use, but still easily useable)
Sure, they're just conventions, not enforced by the language. Nothing's truly private in Python after all "We're all consenting adults here". The leading double underscore does give you a little more protection, but it's still easy enough to bypass manually if you're determined.
Wow. This is good stuff. Thanks. For now, even though this runs counter to the recommendation in the help topic (and yours), I am keeping the object open. After I have tested it more, I want to give thought to "what is dangerous if someone else reuses it ... and that I think should drive the design decision on what should be protected (or at least discouraged from use). This is all great stuff for my learning process. The object posted here is still under development and will get inherited in another object that processes the record.txt file specific to its structure.
|
2

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.