Check Subclass and Superclass in Python: issubclass, __bases__
In Python, you can use the built-in issubclass()
function to check if a class is a subclass (child class) of another.
Additionally, you can get all superclasses of a class using the __mro__
attribute, direct superclasses using the __bases__
attribute, and all subclasses using the __subclasses__()
method.
For methods to get and check the type of an object, see the following article.
Check if a class is a subclass: issubclass()
Use the built-in issubclass()
function to check if a class is a subclass (child class) of another.
issubclass()
returns True
if the class in the first argument is a subclass of the class in the second. Note that a class is considered a subclass of itself.
For example, you can confirm that the boolean type bool
is a subclass of the integer type int
as follows.
print(issubclass(bool, int))
# True
print(issubclass(bool, float))
# False
print(issubclass(bool, bool))
# True
The second argument can be a tuple of classes. It returns True
if the first class is a subclass of any of the classes in the tuple.
print(issubclass(bool, (int, float)))
# True
print(issubclass(bool, (str, float)))
# False
issubclass()
also returns True
for higher-level parent classes, not just direct superclasses.
For example, consider the inheritance chain of exception types: BaseException
-> Exception
-> ArithmeticError
-> ZeroDivisionError
.
print(issubclass(ZeroDivisionError, ArithmeticError))
# True
print(issubclass(ZeroDivisionError, Exception))
# True
print(issubclass(ZeroDivisionError, BaseException))
# True
The first argument of issubclass()
must be a class. Specifying an instance (object) will result in an error.
# print(issubclass(True, int))
# TypeError: issubclass() arg 1 must be a class
print(issubclass(type(True), int))
# True
type()
can be used to get the class of an object, but isinstance()
is more appropriate for checking if an object is an instance of a specific class.
Like issubclass()
, isinstance()
allows you to specify a higher-level parent class or a tuple of multiple classes as the second argument.
print(isinstance(True, bool))
# True
print(isinstance(True, int))
# True
print(isinstance(True, float))
# False
print(isinstance(True, (int, float)))
# True
For more details, see the following article.
Get all superclasses of a class: __mro__
Use the __mro__
attribute to get all superclasses (parent classes) of a class. MRO stands for Method Resolution Order.
The object
class is the superclass of all classes.
print(bool.__mro__)
# (<class 'bool'>, <class 'int'>, <class 'object'>)
print(type(True).__mro__)
# (<class 'bool'>, <class 'int'>, <class 'object'>)
__mro__
returns a tuple of type
objects.
print(type(bool.__mro__))
# <class 'tuple'>
print(type(bool.__mro__[0]))
# <class 'type'>
To get class names, you can access the __name__
attribute of type
. The following example uses list comprehension.
print([c.__name__ for c in bool.__mro__])
# ['bool', 'int', 'object']
Here is how it looks for exception classes. The pprint
module is used to enhance readability.
import pprint
pprint.pprint(ZeroDivisionError.__mro__)
# (<class 'ZeroDivisionError'>,
# <class 'ArithmeticError'>,
# <class 'Exception'>,
# <class 'BaseException'>,
# <class 'object'>)
Generally, it follows the superclass order starting from the class itself, but not all adjacent classes necessarily have a direct parent-child relationship. For example, in the case of multiple inheritance as shown below, BaseA
and BaseB
are sequentially listed in __mro__
without being directly related.
class BaseA(): pass
class BaseB(): pass
class Sub(BaseA, BaseB): pass
pprint.pprint(Sub.__mro__)
# (<class '__main__.Sub'>,
# <class '__main__.BaseA'>,
# <class '__main__.BaseB'>,
# <class 'object'>)
Get direct superclasses of a class: __bases__
Use the __bases__
attribute to get only the direct superclasses (parent classes). Unlike __mro__
, it does not trace back to a higher-level parent.
print(bool.__bases__)
# (<class 'int'>,)
__bases__
returns a tuple of type
objects. For a single direct superclass, the tuple has one element.
print(type(bool.__bases__))
# <class 'tuple'>
print(type(bool.__bases__[0]))
# <class 'type'>
For object
, it is an empty tuple.
print(object.__bases__)
# ()
For classes with multiple inheritance, it is a tuple with multiple elements.
class BaseA(): pass
class BaseB(): pass
class Sub(BaseA, BaseB): pass
print(Sub.__bases__)
# (<class '__main__.BaseA'>, <class '__main__.BaseB'>)
Note that there is also the __base__
attribute, but it can only obtain one superclass in classes with multiple inheritance.
print(bool.__base__)
# <class 'int'>
print(Sub.__base__)
# <class '__main__.BaseA'>
Get all subclasses of a class: __subclasses__()
Use the __subclasses__()
method to get all subclasses (child classes) of a class.
Below is an example with exception classes. The pprint
module is used to make it more readable.
import pprint
pprint.pprint(ArithmeticError.__subclasses__())
# [<class 'FloatingPointError'>,
# <class 'OverflowError'>,
# <class 'ZeroDivisionError'>,
# <class 'decimal.DecimalException'>]
__subclasses__()
returns a list of type
objects.
print(type(ArithmeticError.__subclasses__()))
# <class 'list'>
print(type(ArithmeticError.__subclasses__()[0]))
# <class 'type'>
It includes only the direct subclasses.
class Base(): pass
class SubA(Base): pass
class SubB(Base): pass
class SubSubA(SubA): pass
class SUbSubB(SubB): pass
print(Base.__subclasses__())
# [<class '__main__.SubA'>, <class '__main__.SubB'>]
Some examples of recursively retrieving all subclasses can be found in the following Stack Overflow thread.
An example using a set
is as follows.
# https://stackoverflow.com/a/3862957
def all_subclasses(cls):
return set(cls.__subclasses__()).union(
[s for c in cls.__subclasses__() for s in all_subclasses(c)])
pprint.pprint(all_subclasses(Base))
# {<class '__main__.SubA'>,
# <class '__main__.SubB'>,
# <class '__main__.SubSubA'>,
# <class '__main__.SUbSubB'>}
Note that the results of __subclasses__()
are updated with module imports and other changes.
print(len(dict.__subclasses__()))
# 24
import pandas as pd
print(len(dict.__subclasses__()))
# 29
The example above is executed in Jupyter Notebook, where various modules have been imported by IPython.