Thursday, March 31, 2011

How to dynamically load a Python class

Given a string of a Python class, e.g. 'my_package.my_module.MyClass', what is the best possible way to load it?

In other words I am looking for a Class.forName() function in Python. It needs to work on Google App Engine.

Preferably this would be a function that accepts the FQN of the class as a string, and returns a reference to the class:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()
From stackoverflow
  • module = __import__("my_package/my_module")
    the_class = getattr(module, "MyClass")
    obj = the_class()
    
    Jason Baker : Note that this works because of a bug in the __import__ function. File paths should *not* be used in the __import__ function and will not work in python 2.6 and above: http://docs.python.org/whatsnew/2.6.html#porting-to-python-2-6
  • From the python documentation, here's the function you want:

    def my_import(name):
        mod = __import__(name)
        components = name.split('.')
        for comp in components[1:]:
            mod = getattr(mod, comp)
        return mod
    

    The reason a simple __import__ won't work is because any import of anything past the first dot in a package string is an attribute of the module you're importing. Thus, something like this won't work:

    __import__('foo.bar.baz.qux')
    

    You'd have to call the above function like so:

    my_import('foo.bar.baz.qux')
    

    Or in the case of your example:

    klass = my_import('my_package.my_module.my_class')
    some_object = klass()
    

    EDIT: I was a bit off on this. What you're basically wanting to do is this:

    from my_package.my_module import my_class
    

    The above function is only necessary if you have a empty fromlist. Thus, the appropriate call would be like this:

    mod = __import__('my_package.my_module', globals(), locals(), ['my_class'])
    klass = getattr(mod, 'my_class')
    

    Note that the last three arguments don't really do much other than provide context (so even though a list with 'my_class' in it was passed, my_class won't be imported into the local namespace).

    pjesi : I tried my_import('my_package.my_module.my_class') but get no module found my_class, which makes sense since it is a class not a module. Howver if I can use gettattr to get the class after the call to my_import
    Jason Baker : That's odd. Everything past the first dot is called using getattr. There shouldn't be any difference.
    Jason Baker : Figured it out. See the post edit.
    pjesi : Thanks I think this is the best way. Now I only need the best way to split the string 'my_pakcage.my_module.my_class' into mod_name, klass_name but I guess I can figure that out :)

0 comments:

Post a Comment