03 December 2011 2 comments Python
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
class Farm(object): def close(self): print "Closing" from contextlib import closing with closing(Farm()) as farm: pass # this will print: # Closing
closing() decorator "steals" the
__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
__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.