Question

If I have Python code

class A():
    pass
class B():
    pass
class C(A, B):
    pass

and I have class C, is there a way to iterate through it's super classed (A and B)? Something like pseudocode:

>>> magicGetSuperClasses(C)
(<type 'A'>, <type 'B'>)

One solution seems to be inspect module and getclasstree function.

def magicGetSuperClasses(cls):
    return [o[0] for o in inspect.getclasstree([cls]) if type(o[0]) == type]

but is this a "Pythonian" way to achieve the goal?

Was it helpful?

Solution

C.__bases__ is an array of the super classes, so you could implement your hypothetical function like so:

def magicGetSuperClasses(cls):
  return cls.__bases__

But I imagine it would be easier to just reference cls.__bases__ directly in most cases.

OTHER TIPS

@John: Your snippet doesn't work -- you are returning the class of the base classes (which are also known as metaclasses). You really just want cls.__bases__:

class A: pass
class B: pass
class C(A, B): pass

c = C() # Instance

assert C.__bases__ == (A, B) # Works
assert c.__class__.__bases__ == (A, B) # Works

def magicGetSuperClasses(clz):
  return tuple([base.__class__ for base in clz.__bases__])

assert magicGetSuperClasses(C) == (A, B) # Fails

Also, if you're using Python 2.4+ you can use generator expressions instead of creating a list (via []), then turning it into a tuple (via tuple). For example:

def get_base_metaclasses(cls):
    """Returns the metaclass of all the base classes of cls."""
    return tuple(base.__class__ for base in clz.__bases__)

That's a somewhat confusing example, but genexps are generally easy and cool. :)

The inspect module was a good start, use the getmro function:

Return a tuple of class cls’s base classes, including cls, in method resolution order. No class appears more than once in this tuple. ...

>>> class A: pass
>>> class B: pass
>>> class C(A, B): pass
>>> import inspect
>>> inspect.getmro(C)[1:]
(<class __main__.A at 0x8c59f2c>, <class __main__.B at 0x8c59f5c>)

The first element of the returned tuple is C, you can just disregard it.

if you need to know to order in which super() would call the classes you can use C.__mro__ and don't need inspect therefore.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top