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 <[email protected]> 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 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. > 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. I hope this is written clearly enough; Possibly an example for this case should be included in the docstring. I'm not sure though. I'd appreciate any opinions and more critiques. > > On Wed, Jan 5, 2011 at 5:13 PM, cool-RR <[email protected]> wrote: > >> Yes, I agree that's kind of an opaque description. But I haven't been able >> to come up with a description which (a) explains enough and (b) >> is succinct enough. Do you have a suggestion? >> >> Also, I think you should be sending critiques on the list; Other people >> may have interesting opinions. >> >> >> On Wed, Jan 5, 2011 at 9:29 AM, Tal Einat <[email protected]> wrote: >> >>> "Allows greater freedom" isn't much of a description. I had to read >>> through the entire docstring to understand what it does. You should make it >>> very clear what new functionality this supplies compared to the basic stuff. >>> >>> On Tue, Jan 4, 2011 at 7:55 PM, cool-RR <[email protected]> wrote: >>> >>>> Hello folks. >>>> >>>> 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` >>>> module<https://github.com/cool-RR/GarlicSim/blob/first_context_manager_review/garlicsim/garlicsim/general_misc/context_manager.py>. >>>> 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 >>>> detail. >>>> >>>> Ram. >>>> >>>> Defines the `ContextManager` and `ContextManagerType` classes. >>>> >>>> These classes allow for greater freedom both when (a) defining context >>>> managers >>>> and when (b) using them. >>>> >>>> Inherit all your context managers from `ContextManager` (or decorate >>>> your >>>> generator functions with `ContextManagerType`) to enjoy all the benefits >>>> described below. >>>> >>>> >>>> Defining context managers >>>> ------------------------- >>>> >>>> There are 3 different ways in which context managers can be defined, and >>>> each >>>> 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: >>>> >>>> class MyContextManager(ContextManager): >>>> def __enter__(self): >>>> pass # preparation >>>> def __exit__(self, type_=None, value=None, traceback=None): >>>> pass # cleanup >>>> >>>> 2. As a decorated generator, like so: >>>> >>>> @ContextManagerType >>>> def MyContextManager(): >>>> try: >>>> yield >>>> finally: >>>> 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 >>>> allowed >>>> here that `contextlib` doesn't allow is to yield the context manager >>>> itself >>>> 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: >>>> >>>> class MyContextManager(ContextManager): >>>> def manage_context(self): >>>> do_some_preparation() >>>> try: >>>> with some_lock: >>>> yield self >>>> finally: >>>> do_some_cleanup() >>>> >>>> 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__` in >>>> 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: >>>> do_stuff() >>>> >>>> 2. As a decorator to a function >>>> >>>> @MyContextManager() >>>> def do_stuff(): >>>> 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 >>>> combined >>>> with all the other goodies given by `ContextManager`. >>>> >>>> >>>> That's it. Inherit all your context managers from `ContextManager` (or >>>> decorate >>>> your generator functions with `ContextManagerType`) to enjoy all these >>>> benefits. >>>> >>>> >>>> -- >>>> Sincerely, >>>> Ram Rachum >>>> >>>> _______________________________________________ >>>> Python-il mailing list >>>> [email protected] >>>> http://hamakor.org.il/cgi-bin/mailman/listinfo/python-il >>>> >>>> >>> >> >> >> -- >> Sincerely, >> Ram Rachum >> > > -- Sincerely, Ram Rachum
_______________________________________________ Python-il mailing list [email protected] http://hamakor.org.il/cgi-bin/mailman/listinfo/python-il
