[Python-il] What do you think about my `ContextManager`?

cool-RR cool-rr at cool-rr.com
Thu Jan 6 17:50:22 IST 2011


On Thu, Jan 6, 2011 at 11:58 AM, Tal Einat <taleinat at gmail.com> wrote:

> On Thu, Jan 6, 2011 at 1:33 AM, cool-RR <cool-rr at cool-rr.com> wrote:
>
>> Thanks for the critique Tal.
>>
>> I updated the `context_manager` module in response, here is the new
>> version:
>>
>>
>> https://github.com/cool-RR/GarlicSim/blob/development/garlicsim/garlicsim/general_misc/context_manager.py
>>
>> (Note that this is a link to my `development` branch, so it will get
>> updated as I continue working on it.)
>>
>> In Thu, Jan 6, 2011 at 12:36 AM, Tal Einat <taleinat at gmail.com> wrote:
>>
>>> How about something like: "A class for writing enhanced context managers.
>>> Allows using context managers as decorators, a new succinct way to define
>>> context managers, and some other goodies."
>>>
>>
>> Here's the new description I came up, tell me if you think it's good
>> enough:
>>
>>
>> Defines the `ContextManager` and `ContextManagerType` classes.
>>
>> These classes allow for greater freedom both when (a) defining context
>> managers
>> and when (b) using them. It allows defining context managers either by (1)
>> using the classic `__enter__` and `__exit__` interface, or (2) using a
>> stand-alone generator function or (3) using a class that defines a
>> `manage_context` generator function. In addition, the `ContextManager`
>> class
>> allows using a context manager as a decorator to a function, which for
>> some
>> cases is a better alternative than using the `with` keyword.
>>
>>
> I still find this to be too long, in the sense that I have to read the
> entire paragraph just to get a basic idea of what this does. How about
> keeping this, but adding to the first sentence, something like:
>
>  Defines the `ContextManager` and `ContextManagerType` classes. Using
> these to define context managers allows using such context managers as
> decorators (in addition to their normal use) and supports writing context
> managers in a new form (as well as the original forms).
>

Cool, I replaced mine with this one.


>
>
>>
>>
>>> I must say, the actual benefits are really unclear. How is using
>>> @MyContextManager() better than contextlib.ContextDecorator (the latter
>>> being more explicit)?
>>>
>>
>> How is `ContextDecorator` more explicit? The place where you write
>> "ContextDecorator" is where you *define* you context manager, not where you
>> *use* it. So when you use your context manager as a decorator using
>> Foord's `ContextDecorator`, there is no reference to `ContextDecorator`, so
>> I don't see how it's more explicit.
>>
>
> You are correct, I misunderstood the use of ContextDecorator. So the use is
> very similar. If the two classes are identical in this sense, you should
> mention that, if not you must describe the differences.
>

There's this sentence in the docstring: "This functionality is also
available in the standard library of Python 3.2+ by using
`contextlib.ContextDecorator`, but here it is combined with all the other
goodies given by `ContextManager`."

I think it's good enough: I don't want to start describing `ContextManager`
in terms of Foord's `ContextDecorator`, I'd rather describe it directly.
Also the readers might not be familiar with `ContextDecorator`-- It's a
relatively new addition and I'd bet that the vast majority of Python users
aren't aware of it.


>
>
>>
>>
>>> How is using the "manage_context()" method better than just defining a
>>> context manager with a function and contextlib.contextmanager?
>>>
>>> - Tal
>>>
>>
>> There are two cases that I can think of where it's better. In the version
>> of `context_manager.py` you saw before I gave an example of the first, and
>> in the new version that I linked to above I also explain the second.
>>
>> The first case where this is helpful is when you want a context manager
>> which calls another context manager. For example, this code:
>>
>>   class MyContextManager(ContextManager):
>>      def manage_context(self):
>>          with some_lock:
>>              yield self
>>
>>
>> Is much nicer in my opinion than this code, which is its equivalent:
>>
>>   class MyContextManager(ContextManager):
>>       def __enter__(self):
>>         some_lock.__enter__()
>>         return self
>>     def __exit__(self, *exc):
>>         return some_lock.__exit__(*exc)
>>
>>
>> As for the second case, I'll quote the new version of the docstring:
>>
>>  Another advantage of this approach over `__enter__` and `__exit__` is
>> that
>> it's better at handling exceptions, since any exceptions would be raised
>> inside `manage_context` where we could `except` them, which is much more
>> idiomatic than the way `__exit__` handles exceptions, which is by
>> receiving their type and returning whether to swallow them or not.
>>
>>
> The same can be said for defining context manager via generator functions
> and contextlib.contextmanager. How is your context_manager() form of
> definition better or different than that?
>

It's true, it's the same mechanism as `contextlib.contextmanager`; The
difference is that in `contextlib.contextmanager` you create a bare context
manager which can do nothing beyond being a context manager. But when you
subclass from `ContextManager` and use `manage_context`, you can put
whatever else you want in this class; You can define methods, inherit from
other classes, etc.

For example, if you already have some class `Foobar` in your project and you
want it to behave as a generator-style context manager, inheriting from my
`ContextManager` is the only solution. (Except coding your own, of course.)



>  I hope this is written clearly enough; Possibly an example for this case
>> should be included in the docstring. I'm not sure though.
>>
>
> It is technically clear. However, the reasons someone would want to use it
> instead of the existing forms of writing context managers aren't clear at
> all. You should give actual examples of things that can be done with your
> classes that can't be done otherwise (or would be significantly more
> cumbersome).
>
> - Tal
>

I added an example for the first case now. I tried giving an example for the
second one, but couldn't find an impressive enough example. I have a few
places where it saved me a few dozen characters, but it's not impressive
enough. So I think I'll stay without an example for the second case.

All the changes can be seen in the most updated version here:

https://github.com/cool-RR/GarlicSim/blob/development/garlicsim/garlicsim/general_misc/context_manager.py


Ram.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://hamakor.org.il/pipermail/python-il/attachments/20110106/b9f314f6/attachment-0001.htm>


More information about the Python-il mailing list