[Python-ideas] A different kind of context manager

Haoyi Li haoyi.sg at gmail.com
Mon Oct 21 23:26:06 CEST 2013


> Maybe we should have selected one in which this sort of coding is its
native, natural, form, rather than having this intermarriage kludge which
turns an imperative-looking generator into the traditional context manager.

I agree with this 100%. Unfortunately, Python picked the current style of
`with` statements a while ago, and this would be a pretty huge
change/additional feature.

FWIW, other languages with easy anonymous functions (e.g. ruby, scala) have
this, and it does provide all the benefits that you describe. For example,
spinning off parallel tasklets inline is just a matter of `async{ ... }`
where `async` is just a context manager.

As much as I'd like to see python follow suite, getting it into python
would be a pretty large upheaval and not something that I expect to happen
in the near future.

And the last option, if you're crazy, is to use MacroPy and write your own
tasklet/forking context managers! It's surprisingly easy (< 50 lines).


On Mon, Oct 21, 2013 at 2:16 PM, Kristján Valur Jónsson <
kristjan at ccpgames.com> wrote:

>  **Ø  **Cool, sure. But what are the use cases that need this and can't
> be done easily with the existing design?****
>
> Exactly those I listed.  Any form of execution that requires a “function”
> to be run.  This include all existing threading/multiprocessing designs.**
> **
>
> ** **
>
> **Ø  ** How would making the code inside the with block a callable
> improve this?****
>
> It allows the “if” statement to be part of the context manager ****
>
> ** **
>
> **Ø  **I think this code is easier to read than yours as the logic of
> whether or not the do_stuff_once block is executed is where it belongs --
> not hidden in the context manager.****
>
> That is a matter of taste.  Maybe it would make sense to pull other things
> out of the context manager too?  But taste should not, IMHO, limit our
> options.  If this is a common idiom, locking and executing once, why
> shouldn’t we be able to write a clever macro/context manger/syntactic sugar
> to help us with that?  Why insist on this verbosity?****
>
> ** **
>
> Also, consider my argument that most context managers are written using
> the @contextmanager paradigm.  We like this idiom so much because this is
> what we really want to do, call the code from a wrapper function.****
>
> If you look at the design of that context manager, it is not exactly
> straightforward.  This suggests to me that maybe we took a wrong turn
> deciding on a context manager design.  Maybe we should have selected one in
> which this sort of coding is its native, natural, form, rather than having
> this intermarriage kludge which turns an imperative-looking generator into
> the traditional context manager.****
>
> ** **
>
> ** **
>
> *From:* Bruce Leban [mailto:bruce at leapyear.org]
> *Sent:* 21. október 2013 17:22
> *To:* Kristján Valur Jónsson
> *Cc:* python-ideas at python.org
>
> *Subject:* Re: [Python-ideas] A different kind of context manager****
>
> ** **
>
> ** **
>
> On Mon, Oct 21, 2013 at 6:55 AM, Kristján Valur Jónsson <
> kristjan at ccpgames.com> wrote:****
>
> So, If this is the way people like to think about context managers, like
> writing wrapper functoins, why don‘t we turn them into proper wrapper
> functions?****
>
> <...> The cool thing here though, is that "code" could, for example, be
> run on a different tasklet.  Or a different thread.  Or a different
> universe.****
>
> Cool, sure. But what are the use cases that need this and can't be done
> easily with the existing design?****
>
> ** **
>
> class NewContextManager(object):****
>
>    # A context manager that locks a resource, then executes the code only
> if it is not recursing
>   def __init__(self, lock):
>     self.lock = lock
>   def __contextcall__(self, code):
>     with lock:
>       if lock.active:
>         return  # This is where @contextmanager will stop you, you can’t
> skip the ‘yield’
>       lock.active = True
>       try:
>         return code(None) # optionally pass value to the code as in "with
> foo() as X"
>       finally:
>         lock.active = False****
>
>  ** **
>
> You can do that with current context managers:****
>
> ** **
>
>   with lock_once(x) as lock_acquired:****
>
>     if lock_acquired:  # was not already locked****
>
>         do_stuff_once()****
>
> ** **
>
> @contextmanager****
>
> def lock_once(lock):****
>
>     if lock.active:****
>
>         yield False****
>
>     else:****
>
>         lock.active = True****
>
>         try:****
>
>             yield True****
>
>         finally:****
>
>             lock.active = False****
>
>   ** **
>
> Note that I'm mimicking your lock/unlock code which of course is not the
> proper way to acquire/release a lock, but it gets the idea across. How
> would making the code inside the with block a callable improve this? I
> think this code is easier to read than yours as the logic of whether or not
> the do_stuff_once block is executed is where it belongs -- not hidden in
> the context manager. Note that my version also allows me to do this, which
> I can't easily do with your context manager:****
>
> ** **
>
>    with lock_once(x) as lock_acquired:****
>
>     if lock_acquired:  # was not already locked****
>
>         do_stuff_once()****
>
>     else:****
>
>         log('Lock %r was already acquired', x)****
>
>     do_stuff_every_time()****
>
>   ** **
>
> ** **
>
> --- Bruce
> I'm hiring: http://www.cadencemd.com/info/jobs****
>
> Latest blog post: Alice's Puzzle Page http://www.vroospeak.com****
>
> Learn how hackers think: http://j.mp/gruyere-security****
>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20131021/56b472ef/attachment.html>


More information about the Python-ideas mailing list