[Python-Dev] Timeout for PEP 550 (original) (raw)

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

Nick Coghlan ncoghlan at gmail.com
Tue Oct 17 00:09:27 EDT 2017


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

On Mon, Oct 16, 2017 at 9:11 AM, Yury Selivanov <yselivanov.ml at gmail.com> wrote:

> I agree, but I don't see how making the type a subtype (or duck type) of > MutableMapping prevents any of those strategies. (Maybe you were equating > MutableMapping with "subtype of dict"?)

Question: why do we want EC objects to be mappings? I'd rather make them opaque, which will result in less code and make it more future-proof. I'd rather have them mappings, since that's what they represent. It helps users understand what's going on behind the scenes, just like modules, classes and (most) instances have a _dict_ that you can look at and (in most cases) manipulate.

Perhaps rather than requiring that EC's be mappings, we could instead require that they expose a mapping API as their dict attribute, similar to the way class dictionaries work?

Then the latter could return a proxy that translated mapping operations into the appropriate method calls on the ContextVar being used as the key.

Something like:

class ExecutionContextProxy:
    def __init__(self, ec):
        self._ec = ec
        # Omitted from the methods below: checking if this EC is the
        # active EC, and implicitly switching to it if it isn't (for

read ops) # or complaining (for write ops)

    # Individual operations call methods on the key itself
    def __getitem__(self, key):
        return key.get()
    def __setitem__(self, key, value):
        if not isinstance(key, ContextVar):
            raise TypeError("Execution context keys must be context

variables") key.set(value) def delitem(self, key): key.delete()

    # The key set would be the context vars assigned in the active

context def contains(self, key): # Note: PEP 550 currently calls the below method ec.vars(), # but I just realised that's confusing, given that the vars() builtin # returns a mapping return key in self._ec.assigned_vars() def iter(self): return iter(self._ec.assigned_vars()) def keys(self): return self._ec.assigned_vars()

    # These are the simple iterator versions of values() and items()
    # but they could be enhanced to return dynamic views instead
    def values(self):
        for k in self._ec.assigned_vars():
            yield k.get()
    def items(self):
        for k in self._ec.assigned_vars():
            yield (k, k.get())

The nice thing about defining the mapping API as a wrapper around otherwise opaque interpreter internals is that it makes it clearer which operations are expected to matter for runtime performance (i.e. the ones handled by the ExecutionContext itself), and which are mainly being provided as intuition pumps for humans attempting to understand how execution contexts actually work (whether for debugging purposes, or simply out of curiosity)

If there's a part of the mapping proxy API where we don't have a strong intuition about how it should work, then instead of attempting to guess suitable semantics, we can instead define it as raising RuntimeError for now, and then wait and see if the appropriate semantics become clearer over time.

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/ab38582b/attachment.html>



More information about the Python-Dev mailing list