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!).
On Mon, Oct 16, 2017 at 9:09 PM, Nick Coghlan <ncogh...@gmail.com> wrote: > On 17 October 2017 at 03:00, Guido van Rossum <gu...@python.org> wrote: > >> On Mon, Oct 16, 2017 at 9:11 AM, Yury Selivanov <yselivanov...@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 | ncogh...@gmail.com | Brisbane, Australia > -- --Guido van Rossum (python.org/~guido)
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com