In CPython the following
import collections
issubclass(dict, collections.Mapping)
returns True
. This confuses me a bit, since dict
is a builtin class defined in CTypes and the collections module explicitly relies on the existence of dict
to accomplish some of its functionality. Something other than straightforward inheritance checks must be going on and I can't figure out why this works. Below I provide some of my reasoning that leads to my confusion.
If we look at the inheritance structure of collections.Mapping
we see it inherits from Collection
. Collection
's signature shows that it inherits from Sized
, Iterable
, Container
all of which inherit only from the metaclass ABCmeta
.
But dict
is a builtin, which I thought meant that it was being defined directly as a CType which I thought meant it wouldn't be inheriting from anything.
So, why is it that issubclass(dict, collections.Mapping)
→ True
?
For more context about why this came up see this nbformat issue, in which in attempting to recreate the signature & functionality of dict
's update
we need to know how issubclass(foo, Mapping)
will behave.
Because this:
MutableMapping.register(dict)
It's explicitly register
ed with MutableMapping
, and abc.ABCMeta
defines issubclass
checks so that registered classes are considered subclasses for the purpose of isinstance
and issubclass
checks, using the __instancecheck__
and __subclasscheck__
hooks.
That's because metaclasses can customize what issubclass
and isinstance
return. In case of MutableMapping
this is done via abc.ABCMeta
, which allows to register "virtual subclasses".
For example:
from collections import MutableMapping
class A(object): pass
MutableMapping.register(A)
issubclass(A, MutableMapping) # True
It even works for subclasses of registered subclasses:
class B(object): pass
class C(B): pass
MutableMapping.register(B)
issubclass(C, MutableMapping) # True
The same happens for dict
. So even though it's not a real subclass of MutableMapping
it's still a virtual subclass. Like the second example shows that means that all "real" subclasses of dict
also will be "virtual" subclasses of MutableMapping
.
Note that even simpler ABCs implement subclass checks based on the presence of methods. For example collections.Sized
checks if the class has a __len__
:
from collections import Sized
class D(object):
def __len__(self):
return 1
issubclass(D, Sized) # True
So even without explicit register
this D
will be recognized as valid subclass of Sized
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With