Most C API uses type slots instead looking up in the type's dictionary for methods. But there are few methods used in basic operations which do not have corresponding slots. For example "keys", "__trunc__" and "__length_hint__".
In particularly, "keys" is checked in dict.__init__() and dict.update() with a positional argument to distinguish a mapping from a sequence of key-value pairs. If there is such method, it is called in PyDict_Merge(). Actually "keys" is looked up twice in these operations. PyDict_Merge() is called every time when you have a call like `f(a=1, **kw)` (keyword arguments with var-keyword arguments). It is optimized for dicts, but if kw is something different (for example OrderedDict or mappingproxy) the keys() method is called.
So would not be worth to add slots for keys (and maybe for values and items) to the tp_as_mapping structure?