which one of these is better?
Fredrik Lundh
fredrik at pythonware.com
Thu Oct 26 16:08:39 EDT 2006
John Salerno wrote:
>> Not sure about the with-- I just went to read the PEP on it, and it
>> confused me greatly. :-) So, I don't know.
>
> Ditto. :)
No need to be confused; the "with" statement is actually very simple.
Consider this piece of code:
set things up
try:
do something
finally:
tear things down
If you do this a lot, it would quite convenient if you could put the
"set things up" and "tear things down" code in a library function, so
you could reuse it. You can of course do something like
def controlled_execution(callback):
set things up
try:
callback(thing)
finally:
tear things down
def my_function(thing):
do something
controlled_execution(my_function)
but that's a bit verbose, especially if you need to modify local
variables. Another approach is to use a one-shot generator, and
abuse the for-in statement:
def controlled_execution():
set things up
try:
yield thing
finally:
tear things down
for thing in controlled_execution():
do something with thing
but this looks a bit weird, and doesn't even work in 2.4 and earlier.
So after contemplating a number of alternatives, GvR finally came up
with a generalization of the latter, using an object instead of a
generator to control the behaviour of an external piece of code:
class controlled_execution:
def __enter__(self):
set things up
return thing
def __exit__(self, type, value, traceback):
tear things down
with controlled_execution() as variable:
some code
When the "with" statement is executed, Python evaluates the expression,
calls the __enter__ method on the resulting value (which is called a
"context guard"), and assigns whatever __enter__ returns to the given
variable. Python will then execute the code body, and *no matter what
happens in that code*, call the guard object's __exit__ method.
For extra bonus, the __exit__ method can look at the exception, if any,
and suppress or modify it, if necessary. For example, the following
__exit__ method swallows any TypeError, but lets all other exceptions
through:
def __exit__(self, type, value, traceback):
return isinstance(value, TypeError)
In Python 2.5, the file object has been equipped with __enter__ and
__exit__ methods; the former simply returns the file object itself, and
the latter closes the file:
>>> f = open("x.txt")
>>> f
<open file 'x.txt', mode 'r' at 0x00AE82F0>
>>> f.__enter__()
<open file 'x.txt', mode 'r' at 0x00AE82F0>
>>> f.read(1)
'X'
>>> f.__exit__(None, None, None)
>>> f.read(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file
This wasn't very difficult, was it?
</F>
More information about the Python-list
mailing list