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