0

I have a simple piece of code that tries to give a convenience to file in Python.

class File:
    def __init__(this, *args):
        this._file = file(*args)

    def __del__(this):
        this._file.close()

def createCallForwarder(method):
    return lambda obj,*args: method(obj._file, *args)

_dict = file.__dict__
for (k,v) in zip(_dict.keys(), _dict.values()):
    if not (k.startswith('__') and k.endswith('__')):
        if v.__class__.__name__ == 'method_descriptor':
            File.__dict__[k] = createCallForwarder(v)

# get the repr method
File.__repr__ = createCallForwarder(dict_proxy['__repr__'])

If i change File to inherit from object, it does not let me assign the methods.

Why is it different?

7
  • What in heavens name are you trying to achieve with your code? Why not use a subclass of file, or use a __getattr__ hook to proxy methods? Commented Sep 28, 2013 at 16:48
  • Use setattr if you want to do the same thing in new style classes: setattr(File, k, createCallForwarder(v)) Commented Sep 28, 2013 at 16:50
  • Thanks! That's exactly what I needed. I dont have that much experience with Python. I was just trying to get a File object that closes itself so I don't have to care. I don't want to leak file objects. Commented Sep 28, 2013 at 16:52
  • 2
    Just a style tip: Python, by convention, uses self instead of this. Commented Sep 28, 2013 at 16:54
  • 2
    @AadityaKalsi: Python file objects already do that. They have a __del__ handler of their own. Commented Sep 28, 2013 at 16:56

2 Answers 2

4

You should not be accessing __dict__ directly at all.

Use a __getattr__ method to proxy calls to the underlying self._file object instead:

class File(object):
    def __init__(self, *args):
        self._file = open(*args)

    def __getattr__(self, name):
        return getattr(self._file, name)

I've also switched the code to best-practices; using self instead of this and using open() instead of file().

For new-style objects (inheriting from object), use setattr() to set arbitrary attributes. There is no need to use a call forwarder wrapper, however. You could have taken the bound methods of self._file and set those directly on self too:

class File(object):
    def __init__(self, *args):
        self._file = open(*args)
        for name in dir(self._file):
            setattr(self, name, getattr(self._file, name))

If all you wanted was a file object that auto-closes on garbage collection, then you went through a lot of trouble for nothing. Python file objects already have a __del__ handler that does exactly that. It is just not exposed as an explicit __del__ function, instead the C implementation uses a deallocation function that calls close_the_file(f) when deallocated.

Best practice, however, is to use file objects as context manager, using the with statement:

with open(somefilename) as fileobj:
    # do all sorts with fileobj

# here, fileobj will have been closed automatically.

Quoting from the file.close() documentation:

As of Python 2.5, you can avoid having to call this method explicitly if you use the with statement. For example, the following code will automatically close f when the with block is exited:

from __future__ import with_statement # This isn't required in Python 2.6

with open("hello.txt") as f:
    for line in f:
        print line,
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! That was very helpful and I prefer the getattr way. The only lil problem I have is that it doesn't play well with readline for auto completion. The reason I have this implementation is because I have other objects who may be writing to the same file multiple times, and to <code> open </code> multiple times is costly.
@AadityaKalsi: Proxying the file object doesn't buy you anything in that case. File objects already auto-close in CPython.
@AadityaKalsi: You can implement a __dir__ method perhaps to help with autocompletion.
0

I was just trying to get a File object that closes itself

Use a with statement which will (among other things), close files for you:

with open('somefile.txt') as the_file:
   for line in the_file:
      # do something with line

# Once outside the with block, the file is automatically closed
print('somefile.txt is closed here') 

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.