Pykedout
Pykedout

Reputation: 71

List of specific class names in Python

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

Answers (3)

Don Spaulding
Don Spaulding

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

Ned Batchelder
Ned Batchelder

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

Stephan202
Stephan202

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.

  1. First, define some classes:

    >>> class T: pass
    ... 
    >>> class S: pass
    ... 
    >>> class U(T): pass
    ...
    
  2. 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']
    
  3. 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']
    
  4. 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']
    
  5. 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']
    
  6. 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
    ... 
    
  7. 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

Related Questions