191

Given a class Foo (whether it is a new-style class or not), how do you generate all the base classes - anywhere in the inheritance hierarchy - it issubclass of?

martineau
  • 119,623
  • 25
  • 170
  • 301
Sridhar Ratnakumar
  • 81,433
  • 63
  • 146
  • 187

7 Answers7

241

inspect.getmro(cls) works for both new and old style classes and returns the same as NewClass.mro(): a list of the class and all its ancestor classes, in the order used for method resolution.

>>> class A(object):
>>>     pass
>>>
>>> class B(A):
>>>     pass
>>>
>>> import inspect
>>> inspect.getmro(B)
(<class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
Georgy
  • 12,464
  • 7
  • 65
  • 73
Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
  • 4
    Doesn't work for pyobjc classes :( File "/Users/rbp/Projects/zzzzzzz/macmdtypes.py", line 70, in coerce print inspect.getmro(path) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 348, in getmro _searchbases(cls, result) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 339, in _searchbases for base in cls.__bases__: AttributeError: '__NSTaggedDate' object has no attribute '__bases__' – rbp Aug 08 '13 at 17:11
  • 28
    @rbp I suspect that you had the same problem that I encountered: you were trying to do `inspect.getmro(obj)` instead of `inspect.getmro(type(obj))`. – esmit Jul 09 '15 at 18:40
  • What is "mro" ? – Ben Slade Nov 29 '22 at 17:52
  • @BenSlade Method Resolution Order: https://www.python.org/download/releases/2.3/mro/ – tovicheung Dec 25 '22 at 01:14
53

See the __bases__ property available on a python class, which contains a tuple of the bases classes:

>>> def classlookup(cls):
...     c = list(cls.__bases__)
...     for base in c:
...         c.extend(classlookup(base))
...     return c
...
>>> class A: pass
...
>>> class B(A): pass
...
>>> class C(object, B): pass
...
>>> classlookup(C)
[<type 'object'>, <class __main__.B at 0x00AB7300>, <class __main__.A at 0x00A6D630>]
Crescent Fresh
  • 115,249
  • 25
  • 154
  • 140
  • 6
    This may introduce duplicates. And this is why the documentation for `getmro` explicitly says "No class appears more than once in this tuple"? – Sridhar Ratnakumar Sep 09 '09 at 20:45
  • 12
    Caution, `__bases__` only goes up **one level**. (As your recursive utility implies, but a cursory glance at the example might not pick up on that.) – Bob Stein Mar 18 '16 at 14:31
44

inspect.getclasstree() will create a nested list of classes and their bases. Usage:

inspect.getclasstree(inspect.getmro(IOError)) # Insert your Class instead of IOError.
Huge
  • 661
  • 7
  • 14
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • 3
    Ooh, nice. And for even nicer output, use pprint! `python -c 'import inspect; from pprint import pprint as pp; pp(inspect.getclasstree(inspect.getmro(IOError)))'` – penguin359 Nov 15 '16 at 04:58
30

According to the Python doc, we can also simply use class.__mro__ attribute or class.mro() method:

>>> class A:
...     pass
... 
>>> class B(A):
...     pass
... 
>>> B.__mro__
(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
>>> A.__mro__
(<class '__main__.A'>, <class 'object'>)
>>> object.__mro__
(<class 'object'>,)
>>>
>>> B.mro()
[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
>>> A.mro()
[<class '__main__.A'>, <class 'object'>]
>>> object.mro()
[<class 'object'>]
>>> A in B.mro()
True

YaOzI
  • 16,128
  • 9
  • 76
  • 72
21

you can use the __bases__ tuple of the class object:

class A(object, B, C):
    def __init__(self):
       pass
print A.__bases__

The tuple returned by __bases__ has all its base classes.

codeforester
  • 39,467
  • 16
  • 112
  • 140
mandel
  • 2,921
  • 3
  • 23
  • 27
19

In python 3.7 you don't need to import inspect, type.mro will give you the result.

>>> class A:
...   pass
... 
>>> class B(A):
...   pass
... 
>>> type.mro(B)
[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
>>>

attention that in python 3.x every class inherits from base object class.

Serjik
  • 10,543
  • 8
  • 61
  • 70
  • Same thing seems to apply in my case as in @esmit's comment on the [answer currently below this one](https://stackoverflow.com/a/1401900): `type.mro(my_obj)` fails with `TypeError: descriptor 'mro' for 'type' objects doesn't apply to a 'my_obj' object`; `type.mro(type(my_obj))` works. Not sure if that's relevant: `my_obj` is an instance of a Pydantic model. – ssc Oct 30 '21 at 13:05
  • According to [YaOzI's answer](https://stackoverflow.com/a/56965847/2932052), there is no need to import anything when using the [`mro()` method (or `__mro__` attribute) of the class](https://docs.python.org/3/library/stdtypes.html#special-attributes). Is there an advantage in using `type.mro()`? – Wolf Jan 18 '23 at 13:05
2

Although Jochen's answer is very helpful and correct, as you can obtain the class hierarchy using the .getmro() method of the inspect module, it's also important to highlight that Python's inheritance hierarchy is as follows:

ex:

class MyClass(YourClass):

An inheriting class

  • Child class
  • Derived class
  • Subclass

ex:

class YourClass(Object):

An inherited class

  • Parent class
  • Base class
  • Superclass

One class can inherit from another - The class' attributed are inherited - in particular, its methods are inherited - this means that instances of an inheriting (child) class can access attributed of the inherited (parent) class

instance -> class -> then inherited classes

using

import inspect
inspect.getmro(MyClass)

will show you the hierarchy, within Python.

Jenobi
  • 368
  • 4
  • 12