Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is issubclass(dict, collections.Mapping) true in CPython?

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.

like image 484
mpacer Avatar asked Oct 11 '25 14:10

mpacer


2 Answers

Because this:

MutableMapping.register(dict)

It's explicitly registered 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.

like image 96
user2357112 supports Monica Avatar answered Oct 14 '25 05:10

user2357112 supports Monica


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.

like image 45
MSeifert Avatar answered Oct 14 '25 04:10

MSeifert



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!