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?
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With