This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author josh.r
Recipients jab, josh.r
Date 2021-02-18.01:43:41
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1613612622.04.0.302431597677.issue43246@roundup.psfhosted.org>
In-reply-to
Content
The cause is in dict_merge (see here: https://github.com/python/cpython/blob/master/Objects/dictobject.c ); it has a fast path for when the object being merged in (which is what the dict constructor does; it makes an empty dict, then merges the provided dict-like) is:

1. A dict (or subclass thereof)
2. Which has not overridden __iter__

When that's the case, it assumes it's "dict-compatible" and performs the merge with heavy use of dict-internals. When it's not the case (as in your simple wrapper), it calls .keys() on the object, iterates that, and uses it to pull values via bracket lookup-equivalent code.

I assume the choice of testing __iter__ (really, the C slot for tp_iter, which is equivalent) is for performance; it's more expensive to check if keys was overridden and/or if the __getitem__ implementation (of which there is more than one possibility for slots at the C layer) has been overridden.

What the code is doing is probably logically wrong, but it's significantly faster than doing it the right way, and easy to work around (if you're writing your own dictionary-like thing with wildly different semantics, collections.abc.MutableMapping is probably a better base class to avoid inheriting dict-specific weirdness), so it's probably not worth fixing. Leaving open for others to discuss.
History
Date User Action Args
2021-02-18 01:43:42josh.rsetrecipients: + josh.r, jab
2021-02-18 01:43:42josh.rsetmessageid: <1613612622.04.0.302431597677.issue43246@roundup.psfhosted.org>
2021-02-18 01:43:42josh.rlinkissue43246 messages
2021-02-18 01:43:41josh.rcreate