[Python-ideas] An improved `ContextManager`
cool-rr at cool-rr.com
Tue Jan 4 03:28:25 CET 2011
Ever since Michael Foord talked about `ContextDecorator` in python-ideas
I've been kicking around an idea for my own take on it. It's a
`ContextManager` class which provides the same thing that Foord's
`ContextDecorator` does, but also provides a few more goodies, chief of
which being the `manage_context` method.
I've been working on this for a few days and I think it's ready for review.
It's well-tested and extensively documented. I started using it wherever I
have context managers in GarlicSim.
I'll be happy to get your opinions on my approach and any critiques you may
have. If there are no problems with this approach, I'll probably release it
with GarlicSim 0.6.1 and blog about it.
Here is my `context_manager`
Here are its tests<https://github.com/cool-RR/GarlicSim/tree/first_context_manager_review/garlicsim/test_garlicsim/test_general_misc/test_context_manager>
Following is the module's docstring which explains the module in more
Defines the `ContextManager` and `ContextManagerType` classes.
These classes allow for greater freedom both when (a) defining context
and when (b) using them.
Inherit all your context managers from `ContextManager` (or decorate your
generator functions with `ContextManagerType`) to enjoy all the benefits
Defining context managers
There are 3 different ways in which context managers can be defined, and
has their own advantages and disadvantages over the others.
1. The classic way to define a context manager is to define a class with
`__enter__` and `__exit__` methods. This is allowed, and if you do this
you should still inherit from `ContextManager`. Example:
pass # preparation
def __exit__(self, type_=None, value=None, traceback=None):
pass # cleanup
2. As a decorated generator, like so:
pass # clean-up
This usage is nothing new; It's also available when using the standard
library's `contextlib.contextmanager` decorator. One thing that is
here that `contextlib` doesn't allow is to yield the context manager
by doing `yield SelfHook`.
3. The third and novel way is by defining a class with a `manage_context`
method which returns a decorator. Example:
This approach is sometimes cleaner than defining `__enter__` and
`__exit__`; Especially when using another context manager inside
`manage_context`. In our example we did `with some_lock` in our
`manage_context`, which is shorter and more idiomatic than calling
`some_lock.__enter__` in an `__enter__` method and `some_lock.__exit__`
an `__exit__` method.
These were the different ways of *defining* a context manager. Now let's see
the different ways of *using* a context manager:
Using context managers
There are 2 different ways in which context managers can be used:
1. The plain old honest-to-Guido `with` keyword:
with MyContextManager() as my_context_manager:
2. As a decorator to a function
pass # doing stuff
When the `do_stuff` function will be called, the context manager will be
used. This functionality is also available in the standard library of
Python 3.2+ by using `contextlib.ContextDecorator`, but here it is
with all the other goodies given by `ContextManager`.
That's it. Inherit all your context managers from `ContextManager` (or
your generator functions with `ContextManagerType`) to enjoy all these
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Python-ideas