type
is not a regular class. It is the metaclass of all classes in python. That means that class methods like mro()
or __subclasscheck__()
are defined as regular methods on the type
metaclass, and can be used as bound methods only on instances of that metaclass, i.e. all python classes except for type
itself.
For example, let's experiment with the classes int
and object
.
First, let's make it clear that type
is the metaclass of both classes:
isinstance(object, type) # True
isinstance(int, type) # True
issubclass(object, type) # False
issubclass(int, type) # False
But, as int
inherits from object
, it is a subclass of object
:
issubclass(int, object) # True
Now, what is __subclasscheck__()
?
type(type.__subclasscheck__) # method_descriptor
type(object.__subclasscheck__) # builtin_function_or_method
str(inspect.signature(type.__subclasscheck__)) # (self, subclass, /)
str(inspect.signature(object.__subclasscheck__)) # (subclass, /)
So, __subclasscheck__()
is a method of type
, which means when used as type.__subclasscheck__
it will be unbound, and when used as X.__subclasscheck__
it will be bound to the class X.
Knowing that, you could probably figure out the right way of using __subclasscheck__()
:
# As an unbound method:
type.__subclasscheck__(object, int) # True
# As a bound method:
object.__subclasscheck__(int) # True
Note that both ways are logically equal.
It is also worth noting that if you actually want to check if a class is a subclass of another, you should just be using the builtin function issubclass
.