Welcome, guest | Sign In | My Account | Store | Cart

This recipe allows a base class to keep track of the child classes that inherit from it using a metaclass.

Python, 23 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class ChildTracker(type):
  def __new__(cls, name, bases, dict_):
    new_class = type.__new__(cls, name, bases, dict_)
    # Check if this is the tracking class
    if '__metaclass__' in dict_ and dict_['__metaclass__']==ChildTracker:
      new_class.child_classes = {}
    else:
      # Add the new class to the set
      new_class.child_classes[name] = new_class
    return new_class


class BaseClass(object):
  __metaclass__ = ChildTracker


class Child1(BaseClass):
  pass

class Child2(BaseClass):
  pass

print BaseClass.child_classes.keys()

Every new-style Python class keeps track of its immediate child classes through the __subclass__ method. However, in most cases we also want to know about the grandchildren etc. This is an example of how that can be achieved using metaclasses. An alternative approach could be to walk through the items returned by __subclasses__().

The base class is given the meta class, and the meta class extends the baseclass with a variable 'child_classes'. This variable is a dictionary containing name:class pairs.

A nice feature is that this also works if the child class is located in a different module than the base, unlike some other ways I have seen of finding child classes. However, it can not handle two classes with the same names but in different modules.

It works also during runtime: every time a new child is created, it is added.

1 comment

Alfe 11 years, 11 months ago  # | flag

Why aren't you just using BaseClass.__subclasses__()? Am I missing a point here or are you?

Created by Evert van de Waal on Fri, 18 May 2012 (MIT)
Python recipes (4591)
Evert van de Waal's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks