Getting a list of all classes derived from a base class

Alex Martelli aleaxit at yahoo.com
Mon Apr 3 11:32:07 EDT 2006


Dylan Moreland <dylan.moreland at gmail.com> wrote:
   ...
> > do not use old-style classes: they exist ONLY for backwards
> > compatibility.
   ...
> > and you can call Test.__subclasses__() to get a list of all extant
> > subclassed of Test at any time.
   ...
> Thanks Alex. That's a new one to me -- new-style classes have so many
> strange properties.

You're welcome! Actually, IMHO, it's the _legacy_ style classes which
have odd quirks, as they fail to distinguish cleanly between a type/clas
and its instances, and provide a unified conceptual model.

For example, given an object X which has an attribute named __call__
(has it directly, not from its class/type), does calling X() call
X.__call__()?  In the new-style model, the answer is clear and sharp:
no.  Special methods that Python internally invokes always come from the
type/class, never from the object itself.  In the legacy model, the
answer is fuzzy and muddled: "mostly yes _except_ if X is a class then
no", because if X is a class then X.__call__ is meant to influence the
behavior of calling *instances* of X, only, not that of calling X
itself.

This kind of "conceptual muddle" in oldstyle classes could not be solved
without breaking backwards compatibility, so a parallel concept of
"newstyle" was introduced, and behaves much more simply and predictably;
in Python 3.0, oldstyle will go away -- good riddance!-)

This is quite separate from the fact that, since Python 2.2 where
newstyle objects were introduced, some handy features such as __mro__
and __subclasses__ were introduced -- not to legacy classes, of course,
since you should not use those in new code (not for conceptual reasons).
The "conceptual" side of things can be boiled down to descriptors (and
to a lesser extent, custom metaclasses, but those are rare beasts).


Alex



More information about the Python-list mailing list