I have some classes looking like this:
subs = [Sub3,Sub1]
# Note that this is NOT a list of all subclasses!
# Order is also important
class Sub1(Base): pass
class Sub2(Base): pass
class Sub3(Base): pass
Base.subs = [Sub3,Sub1]
This is a hybrid version of @Ignacio Vazquez-Abrams and @aaronasterling's answers which preserves the order of the subclasses in the list. Initially the subclass names are manually placed in the
subs list in the desired order. Then as each subclass is defined, a class decorator causes the corresponding string to be replaced with the actual subtype.
class Base: @classmethod def registersub(cls, subcls): """ Decorator to register subclass types. """ # replace occurrence(s) of subclass name in 'subs' with the subclass itself while subcls.__name__ in cls.subs: cls.subs[cls.subs.index(subcls.__name__)] = subcls return cls subs = ['Sub3','Sub1'] # some subclass names in some special order @Base.registersub class Sub1(Base): pass @Base.registersub class Sub2(Base): pass @Base.registersub class Sub3(Base): pass print Base.subs # [<class __main__.Sub3>, <class __main__.Sub1>]
It important to note that there's a perhaps subtle difference between my original answer above and the update which follows below -- namely which is that the while the former will work with any class name that is registered with
@Base.registersub, whether or not its a subclass of
I'm pointing this out for two reasons. First because in your comments you said that
subs was a "bunch of classes in a list, some of which might be its subclasses", and more importantly because that is not the case with the code in my update, which only works for
Base subclasses since they are effectively "registered" automatically via the metaclass -- but leave anything other in the list alone.
Exactly the same thing can also be done using a metaclass -- which has the advantage that it eliminates the need to explicitly decorate each subclass as shown in the accepted answer above and instead makes it happen automagically. Note that even though the metaclass's
__init__() is called for the creation of every subclass, it only updates the
subs list if that subclass's name appears in it -- so the initial Base class definition of the contents of
subs still controls what gets put in it and in what order.
class BaseMeta(type): def __init__(cls, name, bases, classdict): if classdict.get('__metaclass__') is not BaseMeta: # subclass? # replace any occurrences of this subclass name # in Base class 'subs' list with the subclass itself while name in cls.subs: cls.subs[cls.subs.index(name)] = cls type.__init__(cls, name, bases, classdict) class Base: __metaclass__ = BaseMeta subs = ['Sub3','Sub1'] # some subclass names in some special order class Sub1(Base): pass class Sub2(Base): pass class Sub3(Base): pass print Base.subs # [<class '__main__.Sub3'>, <class '__main__.Sub1'>]