1

A general situation:

  • I don't know what modules I'll be inspecting beforehand, I don't know what will be in them: classes, methods, etc.
  • I do know what class I'm seeking, and what I need to do with it. e.g. I'll need to run a particular method, cls.register
  • I need to find the most effective way to do this.

I haven't even gotten to specific code, or I'd post it. However I think I have some options:

  1. Just run everything in the module through try/except
  2. if/else seeking for the method I need
  3. Using inspect to find the exact match of classes in the module
  4. Using the meta class to add an attribute this_is_class_sought=True

1-3 seem too crude, 4 seems like too much effort.

My situation:

I trying to integrate Flask-Classy with an application creator/factory.
I have a bunch of view files, I don't know what will be in these files. I need to find all classes that subclass FlaskView, but not FlaskView itself, and then run then class registration function.

So, for example from dir(a_module) for randomly encountered module:

['FlaskView', 'AView', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'forms', 'models', 'redirect', 'render_template', 'request', 'url_for']

I need to determine that AView is there, and run the registration method. 3, above seems likely, but I haven't exactly determined how to differentiate AView, yet.

What is the best way to do this?

EDIT:

I must emphasize that the whole point is that I do not know what modules I'll be looking at, or what they will contain. I need to efficiently extract the information I need and act based on that information.

EDIT2:

__subclasses__() simplifies much for my purposes.

davidism
  • 121,510
  • 29
  • 395
  • 339
blueblank
  • 4,724
  • 9
  • 48
  • 73
  • The normal way to do this is to import all these classes explicitly into the main module. Keeping all these import statements up-to-date will need less effort than writing some magic code that does it for you at runtime. – Markus Unterwaditzer May 28 '13 at 12:51
  • One point I perhaps did not emphasize: I do not know what modules or views I will be getting. I *know* it would be easier to explicitly import the modules but I will not know beforehand which modules I'll be working with, what views they will contain, or how many views they will contain. – blueblank May 28 '13 at 13:03

1 Answers1

0

Sounds like you're trying to do something hacky, but... I'll help out anyhow. If option 4 is an option at all than I would recommend using a self-registering metaclass/baseclass instead.

Take a look at this answer: Generic Python metaclass to keep track of subclasses

copied for completeness

def sublass_registry():
    ''' Create a metaclass to register subclasses '''

    class SublassRegistryMeta(type):
        def __init__(cls, name, bases, classdict):
            if classdict.get('__metaclass__') is SublassRegistryMeta:
                SublassRegistryMeta.lineage = [cls] # put root class at head of a list
            else:
                # sublclasses won't have __metaclass__ explicitly set to this class
                # we know they're subclassees because this ctor is being called for them
                SublassRegistryMeta.lineage.append(cls) # add subclass to list
            type.__init__(cls, name, bases, classdict)

    return SublassRegistryMeta

def subclasses(cls):
    ''' Return a list containing base and subclasses '''

    try:
        if cls.__metaclass__.lineage[0] is cls: # only valid for a root class
            return cls.__metaclass__.lineage
    except AttributeError:
        pass
    return None

class Car(object): # root class
    __metaclass__ = sublass_registry()

class Audi(Car): # inherits __metaclass__
    pass

class Ford(Car): # inherits __metaclass__
    pass

class Audi2(Audi): # sub-subclass also inherits __metaclass__
    pass

print subclasses(Car)
# [<class '__main__.Car'>, <class '__main__.Audi'>, <class '__main__.Ford'>, <class '__main__.Audi2'>]
print subclasses(Audi)
# None

Alternatively, just looping through it with some issubclass and isinstance should do the trick. In general you won't need any try/except here, but for safety you could add some.

Community
  • 1
  • 1
Wolph
  • 78,177
  • 11
  • 137
  • 148