213

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 equivalent Class.forName() in Java, 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()
user
  • 5,119
  • 7
  • 45
  • 62
pjesi
  • 3,641
  • 3
  • 19
  • 15
  • I need to be able to assign the class reference to a variable as well. – pjesi Feb 13 '09 at 22:00
  • 2
    This appears to be a duplicate of: http://stackoverflow.com/questions/452969/does-python-have-an-equivalent-to-java-class-forname – cdleary Feb 13 '09 at 22:42
  • You are right it is a duplicate, thanks for finding it – pjesi Feb 13 '09 at 23:13
  • 1
    @JohnTyree How does loading classes dynamically mean a program isn't interesting? Can you give an example so that this criticism can be more useful to SO members? – Bryan Potts Apr 09 '20 at 20:00
  • 3
    Interesting "enough." It's just a tongue-in-cheek way of saying that doing weird things is sometimes necessary because of factors that you can't control and are hard to predict. The previous comment basically said, "Why don't you just import the normal way?" and I'm saying that they too will someday have a weird corner case that requires doing something ugly. – John Tyree Jul 02 '20 at 00:42

11 Answers11

239

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')
Archit Jain
  • 2,014
  • 1
  • 17
  • 32
Jason Baker
  • 182,027
  • 130
  • 359
  • 509
  • 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 – pjesi Feb 13 '09 at 22:19
  • That's odd. Everything past the first dot is called using getattr. There shouldn't be any difference. – Jason Baker Feb 13 '09 at 22:24
  • 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 :) – pjesi Feb 13 '09 at 22:42
  • The `my_import()` code is not needed, as you can use dots in an `__import__()` call just fine. They all have to refer to module names however. A symbol from the module needs to be fetched with `getattr()`. – vdboor Jun 19 '12 at 14:20
  • If you use mod = __import__(name.split('.')[0]) and then components=name.split('.')[1:] (or equivalent) it works also for classnames. E.g. my_import("datetime.date") – Giacomo d'Antonio Nov 13 '12 at 13:03
  • Your edit solution works without the `fromlist` option (in python 2) i.e. `mod = __import__('my_package.my_module');` `klass = getattr(mod, 'my_class')` is fine. I can't for the life of me work out the effect of `fromlist`, [the documentation](https://docs.python.org/2/library/functions.html#__import__) is not clear to me. – James Owers May 30 '17 at 08:16
  • 2
    python documentation (on the code) of __import__ says to use importlib. so should checkout answer by Adam Spence – naoko Jan 09 '19 at 19:22
  • 1
    Link @naoko is referring to: https://docs.python.org/3/library/importlib.html#importlib.__import__ – Noel Evans Feb 21 '20 at 11:23
169

If you don't want to roll your own, there is a function available in the pydoc module that does exactly this:

from pydoc import locate
my_class = locate('my_package.my_module.MyClass')

The advantage of this approach over the others listed here is that locate will find any python object at the provided dotted path, not just an object directly within a module. e.g. my_package.my_module.MyClass.attr.

If you're curious what their recipe is, here's the function:

def locate(path, forceload=0):
    """Locate an object by name or dotted path, importing as necessary."""
    parts = [part for part in split(path, '.') if part]
    module, n = None, 0
    while n < len(parts):
        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
        if nextmodule: module, n = nextmodule, n + 1
        else: break
    if module:
        object = module
    else:
        object = __builtin__
    for part in parts[n:]:
        try:
            object = getattr(object, part)
        except AttributeError:
            return None
    return object

It relies on pydoc.safeimport function. Here are the docs for that:

"""Import a module; handle errors; return None if the module isn't found.

If the module *is* found but an exception occurs, it's wrapped in an
ErrorDuringImport exception and reraised.  Unlike __import__, if a
package path is specified, the module at the end of the path is returned,
not the package at the beginning.  If the optional 'forceload' argument
is 1, we reload the module from disk (unless it's a dynamic extension)."""
chadrik
  • 3,077
  • 1
  • 20
  • 17
159
import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
Arnaud P
  • 10,957
  • 6
  • 55
  • 64
Adam Spence
  • 2,740
  • 1
  • 19
  • 15
42

If you're using Django you can use import_string.

Yes i'm aware OP did not ask for django, but i ran across this question looking for a Django solution, didn't find one, and put it here for the next boy/gal that looks for it.

# It's available for v1.7+
# https://github.com/django/django/blob/stable/1.7.x/django/utils/module_loading.py
from django.utils.module_loading import import_string

Klass = import_string('path.to.module.Klass')
func = import_string('path.to.module.func')
var = import_string('path.to.module.var')

Keep in mind, if you want to import something that doesn't have a ., like re or argparse use:

re = __import__('re')
Javier Buzzi
  • 5,418
  • 34
  • 43
30
def import_class(cl):
    d = cl.rfind(".")
    classname = cl[d+1:len(cl)]
    m = __import__(cl[0:d], globals(), locals(), [classname])
    return getattr(m, classname)
Stan
  • 4,019
  • 2
  • 29
  • 38
15

Here is to share something I found on __import__ and importlib while trying to solve this problem.

I am using Python 3.7.3.

When I try to get to the class d in module a.b.c,

mod = __import__('a.b.c')

The mod variable refer to the top namespace a.

So to get to the class d, I need to

mod = getattr(mod, 'b') #mod is now module b
mod = getattr(mod, 'c') #mod is now module c
mod = getattr(mod, 'd') #mod is now class d

If we try to do

mod = __import__('a.b.c')
d = getattr(mod, 'd')

we are actually trying to look for a.d.

When using importlib, I suppose the library has done the recursive getattr for us. So, when we use importlib.import_module, we actually get a handle on the deepest module.

mod = importlib.import_module('a.b.c') #mod is module c
d = getattr(mod, 'd') #this is a.b.c.d
Richard Wong
  • 3,258
  • 4
  • 17
  • 19
1

If you happen to already have an instance of your desired class, you can use the 'type' function to extract its class type and use this to construct a new instance:

class Something(object):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(self.name)

one = Something("one")
one.display()
cls = type(one)
two = cls("two")
two.display()
Jason DeMorrow
  • 615
  • 5
  • 8
0

OK, for me that is the way it worked (I am using Python 2.7):

a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()

Then, b is an instance of class 'MyClass'

lfvv
  • 1,469
  • 15
  • 17
0

Python has an inbuilt library importlib to get the job done. :, How to access module method and class method dynamically bypassing package name as a param. An example is given below.

Module 1:

def get_scenario_data():
    return "module1 scenario data"


class Module1:

    def module1_function1(self):
        return "module1_function"

    def module1_function2(self):
        return "module2_function"

Module 2:

def get_scenario_data():
    return "module2 scenario data"



class Module2:

    def module2_function1(self):
        return "module2_function1"

    def module2_function2(self):
        return "module2_function2"

ModuleTest:

  1. Will access the module methods dynamically based on the package name as param
  2. Will access the class methods dynamically based on the package name as param.

ModuleTest

import importlib

module = importlib.import_module('pack1.nestedpack1.module1')
print(module.get_scenario_data())
modul1_cls_obj = getattr(module, 'Module1')()
print(modul1_cls_obj.module1_function1())
print(modul1_cls_obj.module1_function2())

module = importlib.import_module('pack1.nestedpack1.module2')
modul2_cls_obj = getattr(module, 'Module2')()
print(modul2_cls_obj.module2_function1())
print(modul2_cls_obj.module2_function2())
print(module.get_scenario_data())

Results

module1 scenario data
module1_function
module2_function
module2_function1
module2_function2
module2 scenario data
Arpan Saini
  • 3,381
  • 29
  • 43
-1

In Google App Engine there is a webapp2 function called import_string. For more info see here:https://webapp-improved.appspot.com/api/webapp2.html

So,

import webapp2
my_class = webapp2.import_string('my_package.my_module.MyClass')

For example this is used in the webapp2.Route where you can either use a handler or a string.

ph0eb0s
  • 11
-2
module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()
oefe
  • 18,358
  • 7
  • 45
  • 66
  • 6
    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 – Jason Baker Feb 13 '09 at 22:10