Reputation: 71
Is there a way to flag class declarations so that later you can get a list of them flagged?
Or a way to get all classes starting with a certain string ?
Or all classes that are a subclass of a specific class?
Upvotes: 1
Views: 232
Reputation: 774
To get a list of subclasses of your class from within itself, use the __subclasses__ method from the parent class.
>>>class Parent(object):
... pass
...
>>>class Child(Parent):
... pass
...
>>>Parent.__subclasses__()
>>>[<class '__main__.Child'>]
Unfortunately there is a dearth of documentation on this method.
Upvotes: 1
Reputation: 375574
You can also use metaclasses to collect up the classes as they are defined:
class AllSeeingMetaClass(type):
# This will be a list of all the classes that use us as a metaclass.
the_classes = []
def __new__(meta, classname, bases, classDict):
# Invoked as new classes are defined.
print "Defining %r" % classname
new_class = type.__new__(meta, classname, bases, classDict)
meta.the_classes.append(new_class)
return new_class
class MyBase(object):
# A base class that pulls in our metaclass.
__metaclass__ = AllSeeingMetaClass
class Cat(MyBase):
def __init__(self):
pass
class Dog(MyBase):
def __init__(self):
pass
print AllSeeingMetaClass.the_classes
prints:
Defining 'MyBase'
Defining 'Cat'
Defining 'Dog'
[<class '__main__.MyBase'>, <class '__main__.Cat'>, <class '__main__.Dog'>]
Upvotes: 1
Reputation: 61499
Note: in the following I assume Python 3.x. For Python 2.x, use new style classes, i.e. write class T(object): pass
instead of class T: pass
.
First, define some classes:
>>> class T: pass
...
>>> class S: pass
...
>>> class U(T): pass
...
To get a list of classes defined in the current scope, iterate over the globals
(or locals
) and test whether they are an instance of type
(thus a class!) using isinstance
:
>>> [n for n, o in globals().items() if isinstance(o, type)]
['S', 'U', 'T']
Use issubclass
to restrict your search to the subclasses of a given class (in this case T
):
>>> [n for n, o in globals().items() if isinstance(o, type) and issubclass(o, (T,))]
['U', 'T']
You may want to omit T
itself:
>>> [n for n, o in globals().items() if o != T and isinstance(o, type) and issubclass(o, (T,))]
['U']
To get all classes starting with a certain string, call startswith
on the class name:
>>> [n for n, o in globals().items() if n.startswith('T') and isinstance(o, type)]
['T']
To flag certain classes at creation, use a class decorator† to add an attribute, e.g. __flagged__
:
>>> def flag(cls):
... cls.__flag__ = 'flagged'
... return cls
...
>>> @flag
... class X: pass
...
>>> @flag
... class Y: pass
...
>>> class Z: pass
...
Now you can just select only those classed with the __flag__
attribute:
>>> [n for n, o in globals().items() if isinstance(o, type) and hasattr(o, '__flag__')]
['X', 'Y']
†: As bobince notes, class decorators are new in Python 2.6.
Upvotes: 3