[Python-ideas] PEP draft: context variables

Koos Zevenhoven k7hoven at gmail.com
Sat Oct 7 18:40:22 EDT 2017


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. ​​



> but why do you say it's needed? What are these reasons that were missed?
> Do you have a use case?
>
>
​Yes, there's a type of use case. When you think of a generator function as
a function that returns an iterable of values and you don't care about
whether the values are computed lazily or not. In that case, you don't want
next() or .send() to affect the context inside the generator.

​In terms of code, we might want this:

def values():
    # compute some values using cvar.value and
    return a_list_of_values

with cvar.assign(something):
    data = values()

datalist = list(data)


...to be equivalent to:

def values():
    # compute some values using cvar.value and
    # yield them one by one

​with cvar.assign(something):
    data = values()

datalist = list(data)


So we don't want the "lazy evaluation" of generators to affect the values
"in" the iterable. But I think we had our minds too deep in event loops and
chains of coroutines and async generators to realize this.

Initially, this seems to do the wrong thing in many other cases, but in
fact, with the right extension to this behavior, we get the right thing in
almost all situtations. We still do need the other generator behaviors
described in PEP 555, for async and other uses, but I would probably go as
far as making this new one the default. But I kept the decorator syntax for
now.

-- Koos


-- 
+ Koos Zevenhoven + http://twitter.com/k7hoven +
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20171008/febb72dd/attachment.html>


More information about the Python-ideas mailing list