262

In python, I have to instantiate certain class, knowing its name in a string, but this class 'lives' in a dynamically imported module. An example follows:

loader-class script:

import sys
class loader:
  def __init__(self, module_name, class_name): # both args are strings
    try:
      __import__(module_name)
      modul = sys.modules[module_name]
      instance = modul.class_name() # obviously this doesn't works, here is my main problem!
    except ImportError:
       # manage import error

some-dynamically-loaded-module script:

class myName:
  # etc...

I use this arrangement to make any dynamically-loaded-module to be used by the loader-class following certain predefined behaviours in the dyn-loaded-modules...

martineau
  • 119,623
  • 25
  • 170
  • 301
Javier Novoa C.
  • 11,257
  • 13
  • 57
  • 75

10 Answers10

360

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_()
Nam G VU
  • 33,193
  • 69
  • 233
  • 372
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 3
    `module = __import__(module, fromlist=[name])` only worked for me. – umpirsky Jan 09 '12 at 18:18
  • 21
    If anyone is having trouble with the import method Sven mentioned above, I found my code worked better using the following method instead [importlib.import_module](http://docs.python.org/2/library/importlib.html#importlib.import_module). Can be used like: module = importlib.import_module(module_name) – jpennell Nov 27 '12 at 02:37
  • @jpennell you should post that as an answer, it's often more useful to be able to directly use the string returned by `obj.__module__` – Anentropic Aug 22 '14 at 12:42
  • `importlib.import_module` will load the .py file into a pyc if needed as well as handle the complete module.name.pathing.to.get.to.the class. `__import__` will not do either of these things, in a django environment (not tested outside of this) – James Mar 11 '17 at 02:05
170

tl;dr

Import the root module with importlib.import_module and load the class by its name using getattr function:

# Standard import
import importlib
# Load "module.submodule.MyClass"
MyClass = getattr(importlib.import_module("module.submodule"), "MyClass")
# Instantiate the class (pass arguments to the constructor, if needed)
instance = MyClass()

explanations

You probably don't want to use __import__ to dynamically import a module by name, as it does not allow you to import submodules:

>>> mod = __import__("os.path")
>>> mod.join
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'join'

Here is what the python doc says about __import__:

Note: This is an advanced function that is not needed in everyday Python programming, unlike importlib.import_module().

Instead, use the standard importlib module to dynamically import a module by name. With getattr you can then instantiate a class by its name:

import importlib
my_module = importlib.import_module("module.submodule")
MyClass = getattr(my_module, "MyClass")
instance = MyClass()

You could also write:

import importlib
module_name, class_name = "module.submodule.MyClass".rsplit(".", 1)
MyClass = getattr(importlib.import_module(module_name), class_name)
instance = MyClass()

This code is valid in python ≥ 2.7 (including python 3).

Régis B.
  • 10,092
  • 6
  • 54
  • 90
20

Copy-paste snippet:

import importlib
def str_to_class(module_name, class_name):
    """Return a class instance from a string reference"""
    try:
        module_ = importlib.import_module(module_name)
        try:
            class_ = getattr(module_, class_name)()
        except AttributeError:
            logging.error('Class does not exist')
    except ImportError:
        logging.error('Module does not exist')
    return class_ or None
Matthew Hegarty
  • 3,791
  • 2
  • 27
  • 42
Andrejs Cainikovs
  • 27,428
  • 2
  • 75
  • 95
16

Use getattr to get an attribute from a name in a string. In other words, get the instance as

instance = getattr(modul, class_name)()
AFoglia
  • 7,968
  • 3
  • 35
  • 51
14

One can simply use the pydoc.locate function.

from pydoc import locate
my_class = locate("module.submodule.myclass")
instance = my_class()
Xema
  • 1,796
  • 1
  • 19
  • 28
8

If you want this sentence from foo.bar import foo2 to be loaded dynamically, you should do this

foo = __import__("foo")
bar = getattr(foo,"bar")
foo2 = getattr(bar,"foo2")

instance = foo2()
Ahmad Muzakki
  • 1,058
  • 12
  • 17
7

If you want to import a class and method from string, you should do this:

dynamic_import 
│   my_class.py
│      
└───subfolder
│   │   my_subfolder_module.py
│   │

my_subfolder_module.py

 class MySubfolderClass():
        def test_method(self):
            print ("Hello World")

main.py

import importlib 
  
module = importlib.import_module('subfolder.my_subfolder_module')
class_ = getattr(module, "MySubfolderClass")
method_instance = getattr(class_(),"test_method")
method_instance()
#it will output the result of the test method, which is "Hello World"
4

I couldn't quite get there in my use case from the examples above, but Ahmad got me the closest (thank you). For those reading this in the future, here is the code that worked for me.

def get_class(fully_qualified_path, module_name, class_name, *instantiation):
    """
    Returns an instantiated class for the given string descriptors
    :param fully_qualified_path: The path to the module eg("Utilities.Printer")
    :param module_name: The module name eg("Printer")
    :param class_name: The class name eg("ScreenPrinter")
    :param instantiation: Any fields required to instantiate the class
    :return: An instance of the class
    """
    p = __import__(fully_qualified_path)
    m = getattr(p, module_name)
    c = getattr(m, class_name)
    instance = c(*instantiation)
    return instance
SteveJ
  • 3,034
  • 2
  • 27
  • 47
1

Using python globals() seems rational in this case:

# first .py
class first_1:
   inside = 'I am inside first_1 class'


# second.py
from first import *
class seconda:
   inside = 'I am inside seconda'

# third.py
from second import *

instance1 = globals()['first_1']()
print(instance1.inside)
instance2 = globals()['seconda']()
print(instance2.inside)

Out:

python3 third.py 
I am inside first_1 class
I am inside seconda
NotTooTechy
  • 448
  • 5
  • 9
0

Use this snippet code:

def to_class(path:str):
    try:
        from pydoc import locate
        class_instance = locate(path)
    except ImportError:
        print('Module does not exist')
    return class_instance or None

Usage:

if your class name is MyClass and located in my_app.models.MyClass then:

path = "my_app.models.MyClass"
my_class = to_class(path)
Saeed
  • 3,294
  • 5
  • 35
  • 52