[Python-ideas] Yielding through context managers

Guido van Rossum guido at python.org
Tue Jan 8 19:32:00 CET 2013


On Tue, Jan 8, 2013 at 2:13 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
> On Tue, Jan 8, 2013 at 11:06 AM, Guido van Rossum <guido at python.org> wrote:
>> On Sun, Jan 6, 2013 at 9:47 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:
>>> Ah, true, I hadn't thought of that. So yes, any case where the
>>> __exit__ method can be "fire-and-forget" is also straightforward to
>>> implement with just PEP 3156. That takes us back to things like
>>> database transactions being the only ones where
>>
>> And 'yielding' wouldn't do anything about this, would it?
>
> Any new syntax should properly handle the database transaction context
> manager problem, otherwise what's the point? The workarounds for
> asynchronous __next__ and __enter__ methods aren't too bad - it's
> allowing asynchronous __exit__ methods that can only be solved with
> new syntax.

Is your idea that if you write "with yielding x as y: blah" this
effectively replaces the calls to __enter__ and __exit__ with "yield
from x.__enter__()" and "yield from x.__enter__()"? (And assigning the
result of yield fro, x.__enter__() to y.)

>>> I'm not seeing any obvious holes in that strategy, but I haven't
>>> looked closely at the compiler code in a while, so there may be
>>> limitations I haven't accounted for.
>>
>> So would 'yielding' insert the equivalent of 'yield from' or the
>> equivalent of 'yield' in the code?
>
> Given PEP 3156, the most logical would be for it to use "yield from",
> since that is becoming the asynchronous equivalent of a normal
> function call.
>
> Something like:
>
>     with yielding db.session() as :
>         # Do stuff here
>
> Could be made roughly equivalent to:
>
>     _async_cm = db.session()
>     conn = yield from _async_cm.__enter__()
>     try:
>         # Use session here
>     except Exception as exc:
>         # Rollback
>         yield from _async_cm.__exit__(type(exc), exc, exc.__traceback__)
>     else:
>         # Commit
>         yield from _async_cm.__exit__(None, None, None)
>
> Creating a contextlib.contextmanager style decorator for writing such
> asynchronous context managers would be difficult, though, as the two
> different meanings of "yield" would get in each other's way - you
> would need something like "yield EnterResult(expr)" to indicate to
> __enter__ in the wrapper object when to stop. It would probably be
> easier to just write separate __enter__ and __exit__ methods as
> coroutines.
>
> However, note that I just wanted to be clear that I consider the idea
> of a syntax for "asynchronous context managers" plausible, and
> sketched out a possible design to explain *why* I thought it should be
> possible. My focus will stay with PEP 432 until that's done.

Sure, I didn't intend any time pressure. Others may take this up as
well -- or if nobody cares, we can put it off until the need has been
demonstrated more. possibly after Python 3.4 is release.

-- 
--Guido van Rossum (python.org/~guido)



More information about the Python-ideas mailing list