Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a standard function to iterate over base classes?

Tags:

python

I would like to be able to iterate over all the base classes, both direct and indirect, of a given class, including the class itself. This is useful in the case where you have a metaclass that examines an internal Options class of all its bases.

To do this, I wrote the following:

def bases(cls):
    yield cls
    for direct_base in cls.__bases__:
        for base in bases(direct_base):
            yield base

Is there a standard function to do this for me?

like image 448
Conley Owens Avatar asked Nov 04 '10 07:11

Conley Owens


People also ask

Can we iterate class in Python?

To create an object/class as an iterator you have to implement the methods __iter__() and __next__() to your object. As you have learned in the Python Classes/Objects chapter, all classes have a function called __init__() , which allows you to do some initializing when the object is being created.

How do you iterate a function over a list?

We can iterate through a list by using the range() function and passing the length of the list. It will return the index from 0 till the end of the list.

Does Python have base classes?

In Python, abstract base classes provide a blueprint for concrete classes. They don't contain implementation. Instead, they provide an interface and make sure that derived concrete classes are properly implemented. Abstract base classes cannot be instantiated.


2 Answers

There is a method that can return them all, in Method Resolution Order (MRO): inspect.getmro. See here:

http://docs.python.org/library/inspect.html#inspect.getmro

It returns them as a tuple, which you can then iterate over in a single loop yourself:

import inspect
for base_class in inspect.getmro(foo):
    # do something

This has the side benefit of only yielding each base class once, even if you have diamond-patterned inheritance.

like image 60
Amber Avatar answered Sep 28 '22 01:09

Amber


Amber has the right answer for the real world, but I'll show one correct way to do this. Your solution will include some classes twice if two base classes themselves inherit from the same base class.

def bases(cls):
    classes = [cls]
    i = 0
    while 1:
        try:
            cls = classes[i]
        except IndexError:
            return classes
        i += 1
        classes[i:i] = [base for base in cls.__bases__ if base not in classes] 

The only slightly tricky part is where we use the slice. That's necessary to perform this sort of depth first search without using recursion. All it does is take the base classes of the class currently being examined and insert them immediately after it so that the first base class is the next class examined. A very readable solution (that has it's own ugliness) is available in the implementation of inspect.getmro in the standard library.

like image 37
aaronasterling Avatar answered Sep 28 '22 01:09

aaronasterling