Python

Python file with closing automatically


2nd of December 2011

Perhaps someone who knows more about the internals of python and the recent changes in 2.6 and 2.7 can explain this question that came up today in a code review.

I suggest using with instead of try: ... finally: to close a file that was written to. Instead of this:

 dest = file('foo', 'w')
 try:
    dest.write('stuff')
 finally:
    dest.close()
 print open('foo').read()  # will print 'stuff'

We can use this:

 with file('foo', 'w') as dest: 
     dest.write('stuff')
 print open('foo').read()  # will print 'stuff'

Why does that work? I'm guessing it's because the file() instance object has a built in __exit__ method. Is that right?

That means I don't need to use contextlib.closing(thing) right?

For example, suppose you have this class:

 class Farm(object):
    def __enter__(self):
        print "Entering"
        return self
    def __exit__(self, err_type, err_val, err_tb):
        print "Exiting", err_type
        self.close()
    def close(self):
        print "Closing"

 with Farm() as farm:
    pass
 # this will print:
 #   Entering
 #   Exiting None
 #   Closing

Another way to achieve the same specific result would be to use the closing() decrorator:

 class Farm(object):
    def close(self):
        print "Closing"

 from contextlib import closing
 with closing(Farm()) as farm:
    pass
 # this will print:
 #   Closing

So the closing() decorator "steals" the __enter__ and __exit__. This last one can be handy if you do this:

 from contextlib import closing
 with closing(Farm()) as farm:
    raise ValueError

 # this will print
 #  Closing
 #  Traceback (most recent call last):
 #   File "dummy.py", line 16, in <module>
 #     raise ValueError
 #  ValueError

This is turning into my own loud thinking and I think I get it now. contextlib.closing() basically makes it possible to do what I did there with the __enter__ and __exit__ and it seems the file() built-in has a exit handler that takes care of the closing already so you don't have to do it with any extra decorators.



Comment

Show all 1 comments
 

Commenting is currently disabled in Mobile version