Hey guys,

I was just about to fix dict's get() to call __missing__ if a key doesn't exist (before returning the default value) but realized that although small, that patch can cause future issues.
Right now there's an inconsistency:

>>> from collections import UserDict
>>> class A(dict):
...  def __missing__(self, key):
...   print(key)
...
>>> class B(UserDict):
...  def __missing__(self, key):
...   print("UserDict", key)
...
>>> a = A()
>>> b = B()
>>> a.get(123)
>>> b.get(123)
UserDict 123
>>> a.get(123, "abc")
'abc'
>>> b.get(123, "abc")
UserDict 123

The reason for this inconsistency is because the Mapping abc and dict behave differently.
Dict's get doesn't call __getitem__ which causes the call not to route to __missing__.
MutableMapping's get calls __getitem__, which UserDict implements as a check to __missing__ as well.

According to the doc, the specification requires dict's __getitem__ to call __missing__. It doesn't say anything about get().

Should get() call __missing__?

If it does, things like defaultdict.get() might break. It will however be more consistent with dict's specification.
If it doesn't, we expect Mapping to not care about __missing__ as it's only a dict thing, which will require UserDict to override get(). Dict's get() will need to receive a doc update as well stating __missing__ is not called.

Second question is: Is __missing__ only a dict thing, or is it part of the Mapping ABC?

I would expect it to be a part of the Mapping ABC, with subclasses not having to implement it. Right now it's not.

Looking forward for your inputs,
Bar Harel