Josh Rosenberg <shadowranger+pyt...@gmail.com> added the comment:

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.

----------
nosy: +josh.r

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue43246>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to