[Python-ideas] PEP draft: context variables

Nick Coghlan ncoghlan at gmail.com
Mon Oct 9 02:46:13 EDT 2017


On 8 October 2017 at 08:40, Koos Zevenhoven <k7hoven at gmail.com> wrote:

> On Sun, Oct 8, 2017 at 12:16 AM, Nathaniel Smith <njs at pobox.com> wrote:
>
>> On Oct 7, 2017 12:20, "Koos Zevenhoven" <k7hoven at gmail.com> wrote:
>>
>>
>> ​Unfortunately, we actually need a third kind of generator semantics,
>> something like this:
>>
>> @​contextvars.caller_context
>> def genfunc():
>>     assert cvar.value is the_value
>>     yield
>>     assert cvar.value is the_value
>>
>> with cvar.assign(the_value):
>>     gen = genfunc()
>>
>> next(gen)
>>
>> with cvar.assign(1234567890):
>>     try:
>>         next(gen)
>>     except StopIteration:
>>         pass
>>
>> Nick, Yury and I (and Nathaniel, Guido, Jim, ...?) somehow just narrowly
>> missed the reasons for this in discussions related to PEP 550. Perhaps
>> because we had mostly been looking at it from an async angle.
>>
>>
>> That's certainly a semantics that one can write down (and it's what the
>> very first version of PEP 550 did),
>>
>
> ​​I do remember Yury mentioning that the first draft of PEP 550 captured
> something when the generator function was called. I think I started reading
> the discussions after that had already been removed, so I don't know
> exactly what it was. But I doubt that it was *exactly* the above, because
> PEP 550 uses set and get operations instead of "assignment contexts" like
> PEP 555 (this one) does. ​​
>

We didn't forget it, we just don't think it's very useful. However, if you
really want those semantics under PEP 550, you can do something like this:

    def use_creation_context(g):
        @functools.wraps(g)
        def make_generator_wrapper(*args, **kwds):
            gi = g(*args, **kwds)
            return _GeneratorWithCapturedEC(gi)
        return make_generator_wrapper

    class _GeneratorWithCapturedEC:
        def __init__(self, gi):
            self._gi = gi
            self._ec = contextvars.get_execution_context()
        def __next__(self):
            return self.send(None)
        def send(self, value):
            return contextvars.run_with_execution_context(self.ec,
self._gi.send, value)
        def throw(self, *exc_details):
            return contextvars.run_with_execution_context(self.ec,
self._gi.throw, *exc_details)
        def close(self):
            return self.throw(GeneratorExit)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20171009/55fe10dd/attachment.html>


More information about the Python-ideas mailing list