[Python-Dev] Timeout for PEP 550 / Execution Context discussion

Nick Coghlan ncoghlan at gmail.com
Tue Oct 17 01:02:52 EDT 2017


On 17 October 2017 at 14:31, Guido van Rossum <guido at python.org> wrote:

> No, that version just defers to magic in ContextVar.get/set, whereas what
> I'd like to see is that the latter are just implemented in terms of
> manipulating the mapping directly. The only operations for which speed
> matters would be __getitem__ and __setitem__; most other methods just defer
> to those. __delitem__ must also be a primitive, as must __iter__ and
> __len__ -- but those don't need to be as speedy (however __delitem__ must
> really work!).
>

To have the mapping API at the base of the design, we'd want to go back to
using the ContextKey version of the API as the core primitive (to ensure we
don't get name conflicts between different modules and packages), and then
have ContextVar be a convenience wrapper that always accesses the currently
active context:

    class ContextKey:
        ...
    class ExecutionContext:
        ...

    class ContextVar:
        def __init__(self, name):
            self._key = ContextKey(name)

        def get(self):
            return get_execution_context()[self._key]

        def set(self, value):
            get_execution_context()[self._key] = value

        def delete(self, value):
            del get_execution_context()[self._key]

While I'd defer to Yury on the technical feasibility, I'd expect that
version could probably be made to work *if* you were amenable to some of
the mapping methods on the execution context raising RuntimeError in order
to avoid locking ourselves in to particular design decisions before we're
ready to make them.

The reason I say that is because one of the biggest future-proofing
concerns when it comes to exposing a mapping as the lowest API layer is
that it makes the following code pattern possible:

    ec = get_execution_context()
    # Change to a different execution context
    ec[key] = new_value

The appropriate semantics for that case (modifying a context that isn't the
currently active one) are *really* unclear, which is why PEP 550 structures
the API to prevent it (context variables can only manipulate the active
context, not arbitrary contexts).

However, even with a mapping at the lowest layer, a similar API constraint
could still be introduced via a runtime guard in the mutation methods:

    if get_execution_context() is not self:
        raise RuntimeError("Cannot modify an inactive execution context")

That way, to actually mutate a different context, you'd still have to
switch contexts, just as you have to switch threads in C if you want to
modify another thread's thread specific storage.

Cheers,
Nick.

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


More information about the Python-Dev mailing list