[Python-Dev] PEP 567 v2

Nathaniel Smith njs at pobox.com
Fri Jan 5 18:45:00 EST 2018


On Fri, Jan 5, 2018 at 2:43 PM, Chris Jerdonek <chris.jerdonek at gmail.com> wrote:
> One thing that I think could be contributing to confusion around the
> proposed API is that there is a circular relationship between Context
> and ContextVar, e.g. ContextVar.get() does a lookup in the current
> Context with "self" (the ContextVar object) as a key....

It's maybe helpful to remember that while Context is an important part
of the overall API, it's not intended to be "user facing" at all. For
folks writing libraries that need context-local state, they just use
ContextVar and ignore the rest of the API.

> Also, it's the "keys" (the ContextVar objects) that have the get()
> method that should be used rather than the container object (the
> Context). This gives the confusing *feeling* of a mapping of mappings.
> This is different from how the containers people are most familiar
> with work -- like dict.
>
> Is there a reason ContextVar needs to be exposed publicly at all?  For
> example, the API could use string keys like contextvars.get(name) or
> Context.get(name) (class method). There could be separate functions to
> initialize keys with desired default values, etc (internally creating
> ContextVars as needed).
>
> If the issue is key collisions, it seems like this could be handled by
> namespacing or using objects (namespaced by modules) instead of
> strings.

With strings you have the problem of collisions, you lose the ability
to cache values to make ContextVar.get() really fast (which is a
critical requirement for decimal and numpy), and you lose the ability
to detect when a ContextVar has been garbage collected and clean up
its values. (We're not bothering to implement that kind of GC right
now, but it's nice to know that we have the option later if it becomes
a problem.) Allowing arbitrary objects as keys somewhat alleviates the
problem with collisions, but not the others.

What we could do is make the API look like:

import contextvars
key = contextvars.ContextKey(...)
contextvars.set(key, value)
value = contextvars.get(key)

That's isomorphic to the current proposal -- it's just renaming
ContextVar and making the existing get/set methods be globals instead
of methods. So then it's just a question of aesthetics. To me, the
current version looks nicer:

from contextvars import ContextVar
var = ContextVar(...)
var.set(value)
value = var.get()

In particular, you can't reasonably do 'from contextvars import get,
set'; that'd be gross :-). But 'from contextvars import ContextVar' is
fine and gives you the whole user-oriented API in one piece.

-n

-- 
Nathaniel J. Smith -- https://vorpus.org


More information about the Python-Dev mailing list