How to instatiate a class of which the name is only known at runtime?

Peter Otten __peter__ at web.de
Tue Sep 30 03:02:06 EDT 2003


Robert Brewer wrote:

> Peter Otten wrote:
> 
>> Note that all three versions will not work with submodules, e. g.
> "os.path",
>> so let's change it one more (last?) time:
>> 
>> def getClass(classname, modulename):
>>     return getattr(__import__(modulename, globals(), locals(),
> [classname]),
>> classname)
> 
> Thanks, Peter, you finally put me on the right track with regards to
> importing from packages, with that __import__ builtin. Been fighting
> that for a month now, on and off. FWIW, I took your example and expanded
> it into a cookbook recipe, replacing my older, much uglier solution:
> 
> http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223972

Robert, 

note that module names are stored fully qualified in sys.modules so the try
clause in your will always fail with modules like os.path. I have injected
a print statement into your code that should make that clear.

#your code with additional print statement
import sys

def get_func(fullFuncName):
    """Dynamically load a module and retrieve reference to the function."""

    # Parse out the path, module, and function
    atoms = fullFuncName.split(".")
    funcName = atoms.pop()
    moduleName = atoms.pop()
    tPath = ".".join(atoms)

    # See if the module has already been imported. If not, import it.
    try:
        aMod = sys.modules[moduleName]
    except KeyError:
        print "importing", fullFuncName
        if len(atoms) > 0:
            aMod = __import__(tPath + "." + moduleName,
                              globals(), locals(), [''])
        else:
            aMod = __import__(moduleName, globals(), locals())
    aFunc = getattr(aMod, funcName)

    # Assert that the function is a *callable* attribute.
    if not callable(aFunc): raise ImportError(fullFuncError)

    # Return a reference to the function itself,
    # not the results of the function.
    return aFunc

# simple test case
for i in range(2):
    x = get_func("os.path.split")
print x("/home/user/file.txt")

get_func("os.sep") # fails, because fullFuncError is not defined


__import__() does a lookup in sys.modules so that you need not recode it. To
achieve the functionality you want it should be sufficient
to just split module1.module2.func in two parts module1.module2 and func.

#untested
def get_func1(fullName):
    pos = fullName.rfind(".")
    if pos == -1:
        result = getattr(sys.modules["__main__"], fullName)
    else:
        moduleName = fullName[:pos]
        funcName = fullName[pos+1:]
        result = getattr(__import__(moduleName, globals(), locals(),
        [funcName]), funcName)
    if not callable(result):
        raise ImportError(fullName + " is not callable")
    return result

Maybe you should raise a TypeError rather than an ImportError to indicate
that what is expected to be a function is not callable.

Peter




More information about the Python-list mailing list