How to dynamically load a Python class
From the python documentation, here's the function you want:
def my_import(name):
components = name.split('.')
mod = __import__(components[0])
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', fromlist=['my_class'])
klass = getattr(mod, 'my_class')
How do you dynamically load python classes from a given directory?
You are looking for pkgutil.walk_packages
. Using this you can do the following:
def load(root_import_path, is_valid=lambda entity: True):
"""Returns modules in ``root_import_path`` that satisfy the ``is_valid`` test
:param root_import_path: An string name for importing (i.e. "myapp").
:param is_valid: A callable that takes a variable and returns ``True``
if it is of interest to us."""
prefix = root_import_path + u"."
modules = []
for _, name, is_pkg in walk_packages(root_import_path, prefix=prefix):
if is_pkg:
continue
module_code = __import__(name)
contents = dir(module_code)
for thing in contents:
if is_valid(thing):
modules.append(thing)
return modules
Alternatly, if you don't mind taking on a dependency, you could try the straight.plugin
loader, which is a little more complicated than this simple load
function.
Import class from module dynamically
It is expecting my_module
to be a package containing a module named 'my_class'
. If you need to import a class, or an attribute in general, dynamically, just use getattr
after you import the module:
cls = getattr(import_module('my_module'), 'my_class')
Also, yes, it does only work with modules. Remember importlib.import_module
is a wrapper of the internal importlib.__import__
function. It doesn't offer the same amount of functionality as the full import
statement which, coupled with from
, performs an attribute look-up on the imported module.
How to dynamically load class and call method in Python?
I have solved it by little real life help. I had to convert the controller cases from class to module and had to call getattr
twice: Once for the module and once for the method.
Convert the controller case class into an controller case module by removing the class XYZ():
line.
From:
#!/usr/bin/env python
class dummy():
def hello(argv):
print 'Hello World'
To:
#!/usr/bin/env python
def hello(argv):
print 'Hello World'
Change the getattr
code in the controller.
From:
def main(argv):
print 'Number of arguments:', len(sys.argv), 'arguments.'
print 'Argument List:', str(sys.argv)
print 'Load class: ', str(parsed_args.load_class)
print 'Call method: ', str(parsed_args.call_method)
getattr(ControllerCases[parsed_args.load_class], parsed_args.call_method)(argv)
if __name__ == "__main__":
main(sys.argv[1:])
To:
def main(argv):
print 'Number of arguments:', len(sys.argv), 'arguments.'
print 'Argument List:', str(sys.argv)
print 'Load class: ', str(parsed_args.load_class)
print 'Call method: ', str(parsed_args.call_method)
load_class = getattr(ControllerCases, parsed_args.load_class)
call_method = getattr(load_class, parsed_args.call_method)
try:
call_method(argv)
except KeyboardInterrupt:
print 'UserAborted'
if __name__ == "__main__":
main(sys.argv[1:])
Dynamic instantiation from string name of a class in dynamically imported module?
You can use getattr
getattr(module, class_name)
to access the class. More complete code:
module = __import__(module_name)
class_ = getattr(module, class_name)
instance = class_()
As mentioned below, we may use importlib
import importlib
module = importlib.import_module(module_name)
class_ = getattr(module, class_name)
instance = class_()
Import class dynamically in Python
From the documentation on imp.new_module
, the returned module is empty. Meaning that it will never contain your class.
Perhaps what you want to do is add your target directory to sys.path
and use __import__
to dynamically import those modules, then check for your class?
The following code works for me:
modules = ['foo','bar']
for mod in modules:
try:
x = reload(__import__(mod))
except ImportError:
print "bargh! import error!"
continue
try:
cls = getattr(x,'qux')
except AttributeError:
continue
a = cls()
print a.__class__.__name__
Where foo.py
and bar.py
are in the same directory:
#foo.py
class foo(object):
pass
and:
#bar.py
class qux(object):
pass
Instancing classes from dynamically loaded modules
After a lot of messing around, I found that the solution was pretty simple.
I only had to change the way the module gets loaded into a spec like so:
loader = importlib.machinery.SourceFileLoader(filename, dirpath+"/"+filename)
spec = importlib.util.spec_from_loader(loader.name, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
This approached lead to the inspect.getmembers
to return valid classes from the module.
Dynamically load module with Inheritance
You have to import the module itself, then get its class member. You can't just import the class. Assuming your subclass is in a file accessible from the pythonpath as 'animal':
mod = __import__('animal')
spot = mod.Dog(5)
When you import a module, the interpreter first looks to see if a module with that name exists in sys.modules
, then if it fails to find it there, it searches over the pythonpath looking for a package or module matching the given name. If and when it finds one, it parses the code therein, builds a module object out of it, places it on sys.modules
, and returns the module object to the calling scope to be bound to the name it was imported with in the given namespace. All the items in the module (classes, variables, functions) in the module scope (not nested inside something else in the code) are then available as members of that module instance.
Edit:
In response to your comment, the real problem is that you are trying to look up an attribute of the module dynamically, not that you are trying to import anything dynamically. The most direct way to do that would be:
import sub_animal
getattr(sub_animal, 'Dog')
However, if you are trying to dynamically determine the class to initialize based upon some conditions, you probably want to read up on the factory pattern, and possibly decorator
s or even metaclass
es, so that you can dynamically add subclasses automatically to the factory.
class AnimalFactory(type):
animal_classes = {}
def __new__(cls, name, bases, attrs):
new_class = super(AnimalFactory, cls).__new__(cls, name, bases, attrs)
AnimalFactory.animal_classes[name] = new_class
return new_class
@classmethod
def build(cls, name, *args, **kwargs):
try:
klass = cls.animal_classes[name]
except KeyError:
raise ValueError('No known animal %s' % name)
return klass(*args, **kwargs)
class Animal(object):
__metaclass__ = AnimalFactory
def __init__(self, age):
self.age = age
def speak(self):
raise NotImplementedError()
# As long as the file it is implemented in is imported at some point,
# the following can be anywhere
class Dog(Animal):
def speak(self):
return 'woof'
# And then to use, again, anywhere
new_animal = AnimalFactory.build('Dog', 5)
Related Topics
Get Name of Current Script in Python
On Localhost, How to Pick a Free Port Number
How to Insert Pandas Dataframe via MySQLdb into Database
How to Dynamically Add/Remove Periodic Tasks to Celery (Celerybeat)
How to Calculate the Sum of All Columns of a 2D Numpy Array (Efficiently)
How to Read File N Lines at a Time
Dll Load Failed When Importing Pyqt5
Syntaxerror: Multiple Statements Found While Compiling a Single Statement
Why Is Tensorflow 2 Much Slower Than Tensorflow 1
Pip or Pip3 to Install Packages for Python 3
List All the Modules That Are Part of a Python Package
How to Force Python to Be 32-Bit on Snow Leopard and Other 32-Bit/64-Bit Questions
Override Python's 'In' Operator
Check If a Number Is Odd or Even in Python
Plot Pandas Dataframe as Bar and Line on the Same One Chart
How to Get All the Contiguous Substrings of a String in Python