[Tutor] Examples of "With....As Statement" in Python

Steven D'Aprano steve at pearwood.info
Tue Jul 10 18:05:32 CEST 2012


James Bell wrote:
> I'm attempting to learn how to use the "with....as" statement in python.
> 
> I've read the documentation and also a few tutorials but I still cannot
> understand the concept. or how this is normally used. Can someone please
> write an example or 2 of simple ways to use the "with statement".
> 
> I understand in java the try...catch...finally block so maybe someone can
> point out the relationship between them.

Java's try...catch...finally is called try...except...finally in Python.

In simple terms, a with-block uses a "context manager" to automatically wrap 
code in a try...finally block so as to ensure that cleanup code runs 
automatically even in the event of an error.

So that's the basic principle. Instead of having to write this *every time* 
you need to process some stuff:

     initialisation code
     try:
         process stuff
     finally:
         clean up code

you can write the initialisation and cleanup code *once* in a context manager, 
then do:

     with context manager:
         process stuff

and have both the initialisation and cleanup code automatically handled by the 
context manager.

So what's a context manager? I'll tell you what they *aren't* -- they are NOT 
a special type or class. Any class can be a context manager if it obeys the 
right protocol:

* the class must have a special method called __enter__

* the class must have a special method called __exit__

Of course, both __enter__ and __exit__ have to get the details right: they 
have to take the right number of arguments, and do the right thing.

Other than than, any class or type can be context managers, and Python comes 
with a few built in. The most important are file objects: any file object is 
also a context manager, so you can say:

with open("myfile.txt") as f:
     process(f)

and the file object will be automatically closed when the with block is done, 
even if an error occurs.

Some other examples (from memory) include decimal Context objects, unittest 
test features, and probably quite a few others.

How do you use a context manager? Easy -- you just call it using "with".

py> with open("rubbish.txt", "w") as fp:
...     fp.write("starting to write...")
...     fp.write(99)  # oops!
...
20
Traceback (most recent call last):
   File "<stdin>", line 3, in <module>
TypeError: must be str, not int
py>
py> open("rubbish.txt").read()
'starting to write...'


Opening the file a second time (this time *without* the with statement) shows 
that despite the error, the text was saved to disk and the file closed without 
any additional effort.


So how do you write your own context manager?

Naturally you can just define a class and give it the appropriate __enter__ 
and __exit__ methods. But there's an easy way. Python has a library to help 
you write context manager objects. Here's a toy example:

import contextlib
@contextlib.contextmanager
def my_manager(obj):
     print("called manager with argument %s" % obj)
     print("setting up manager...")
     try:
         value = ['anything', 'you', 'like', str(obj)]
         yield value
     finally:
         print("cleanup code running...")


Now I can use my_manager in a with-statement:


py> with my_manager(42) as data:
...     print("processing data")
...     data.sort()
...     print(data)
...
called manager with argument 42
setting up manager...
processing data
['42', 'anything', 'like', 'you']
cleanup code running...



-- 
Steven


More information about the Tutor mailing list