119

I have a string, say: abc.def.ghi.jkl.myfile.mymethod. How do I dynamically import mymethod?

Here is how I went about it:

def get_method_from_file(full_path):
    if len(full_path) == 1:
        return map(__import__,[full_path[0]])[0]
    return getattr(get_method_from_file(full_path[:-1]),full_path[-1])


if __name__=='__main__':
    print get_method_from_file('abc.def.ghi.jkl.myfile.mymethod'.split('.'))

I am wondering if the importing individual modules is required at all.

Edit: I am using Python version 2.6.5.

juliomalegria
  • 24,229
  • 14
  • 73
  • 89
lprsd
  • 84,407
  • 47
  • 135
  • 168

9 Answers9

134

From Python 2.7 you can use the importlib.import_module() function. You can import a module and access an object defined within it with the following code:

from importlib import import_module

p, m = name.rsplit('.', 1)

mod = import_module(p)
met = getattr(mod, m)

met()
frm
  • 3,346
  • 1
  • 21
  • 21
38

You don't need to import the individual modules. It is enough to import the module you want to import a name from and provide the fromlist argument:

def import_from(module, name):
    module = __import__(module, fromlist=[name])
    return getattr(module, name)

For your example abc.def.ghi.jkl.myfile.mymethod, call this function as

import_from("abc.def.ghi.jkl.myfile", "mymethod")

(Note that module-level functions are called functions in Python, not methods.)

For such a simple task, there is no advantage in using the importlib module.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • import_from() pointed me in the right direction. `myClass = getattr(__import__("module.to.import", fromlist=["myClassName"]), "myClassName")`. Thanks for the help! – Fydo Mar 19 '14 at 20:21
  • 1
    The `__import__` approach does work. But try running `help(__import__)`. It says "Because this function is meant for use by the Python interpreter and not for general use it is better to use `importlib.import_module()` to programmatically import a module." – twasbrillig Apr 28 '15 at 09:04
  • 7
    @twasbrillig: When I answered this question, Python 2.5 and 2.6 were still in widespread use. Today, it's certainly best to use `importlib` instead. – Sven Marnach Apr 28 '15 at 09:26
  • 1
    Cool, thanks. Might be a good idea to update the answer to reflect this. – twasbrillig Apr 28 '15 at 10:00
34

For Python < 2.7 the builtin method __ import__ can be used:

__import__('abc.def.ghi.jkl.myfile.mymethod', fromlist=[''])

For Python >= 2.7 or 3.1 the convenient method importlib.import_module has been added. Just import your module like this:

importlib.import_module('abc.def.ghi.jkl.myfile.mymethod')

Update: Updated version according to comments (I must admit I didn't read the string to be imported till the end and I missed the fact that a method of a module should be imported and not a module itself):

Python < 2.7 :

mymethod = getattr(__import__("abc.def.ghi.jkl.myfile", fromlist=["mymethod"]))

Python >= 2.7:

mymethod = getattr(importlib.import_module("abc.def.ghi.jkl.myfile"), "mymethod")
gecco
  • 17,969
  • 11
  • 51
  • 68
  • 7
    Neither of these solutions will not work because the first parameter must be a *module name* in both `__import__()` and `importlib.import_module()`. – Kris Hardy Jan 09 '12 at 15:02
  • 1
    importlib.import_module('abc.def.ghi.jkl.myfile.mymethod') will not work because you have to specify "what module to import in absolute or relative terms" and not the "qualified" name of the method. – frm Jan 09 '12 at 15:04
  • This does not work, obviously, as the first parameter to __import__ should be a module, not a string. – lprsd Jan 09 '12 at 15:04
16
from importlib import import_module

name = "file.py".strip('.py')
# if Path like : "path/python/file.py" 
# use name.replaces("/",".")

imp = import_module(name)

# get Class From File.py
model = getattr(imp, "classNameImportFromFile")

NClass = model() # Class From file 
Cabbage soup
  • 1,344
  • 1
  • 18
  • 26
Alaa Aqeel
  • 615
  • 8
  • 16
  • 3
    Thanks for the answer, just one small problem: I don't think `.strip()` behaves correctly in the case you stated. Specifically, if the file starts with "py", those characters will be removed as well. For example, `"pyfile.py".strip(".py")` produces `"file"`, where it'd be preferred that it produce `"pyfile"` in this case. `name.replace(".py","")` works just fine, though. – jxmorris12 Jun 05 '20 at 19:23
13

It's unclear what you are trying to do to your local namespace. I assume you want just my_method as a local, typing output = my_method()?

# This is equivalent to "from a.b.myfile import my_method"
the_module = importlib.import_module("a.b.myfile")
same_module = __import__("a.b.myfile")
# import_module() and __input__() only return modules
my_method = getattr(the_module, "my_method")

# or, more concisely,
my_method = getattr(__import__("a.b.myfile"), "my_method")
output = my_method()

While you only add my_method to the local namespace, you do load the chain of modules. You can look at changes by watching the keys of sys.modules before and after the import. I hope this is clearer and more accurate than your other answers.

For completeness, this is how you add the whole chain.

# This is equivalent to "import a.b.myfile"
a = __import__("a.b.myfile")
also_a = importlib.import_module("a.b.myfile")
output = a.b.myfile.my_method()

# This is equivalent to "from a.b import myfile"
myfile = __import__("a.b.myfile", fromlist="a.b")
also_myfile = importlib.import_module("a.b.myfile", "a.b")
output = myfile.my_method()

And, finally, if you are using __import__() and have modified you search path after the program started, you may need to use __import__(normal args, globals=globals(), locals=locals()). The why is a complex discussion.

Ondrej Slinták
  • 31,386
  • 20
  • 94
  • 126
Charles Merriam
  • 19,908
  • 6
  • 73
  • 83
  • Your first example of `the_module` and `same_module` is wrong and produce different results. Downvoting. – SleepyCal Jul 22 '14 at 13:24
2

This website has a nice solution: load_class. I use it like this:

foo = load_class(package.subpackage.FooClass)()
type(foo) # returns FooClass

As requested, here is the code from the web link:

import importlib

def load_class(full_class_string):
    """
    dynamically load a class from a string
    """

    class_data = full_class_string.split(".")
    module_path = ".".join(class_data[:-1])
    class_str = class_data[-1]

    module = importlib.import_module(module_path)
    # Finally, we retrieve the Class
    return getattr(module, class_str)
the-typist
  • 119
  • 5
kingaj
  • 611
  • 6
  • 13
0

Use importlib (2.7+ only).

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
-1

How about this :

def import_module(name):

    mod = __import__(name)
    for s in name.split('.')[1:]:
        mod = getattr(mod, s)
    return mod
Aymen Alsaadi
  • 1,329
  • 1
  • 11
  • 12
  • Using the magic method is discouraged. Use importlib instead. – dephinera Nov 01 '20 at 12:22
  • Can you elaborate on why it is discouraging? @dephinera – Aymen Alsaadi Nov 01 '20 at 19:24
  • Well because magic methods are intended to be called by the interpreter, not explicitly by our code. By calling them explicitly, we rely that their signature will never change, however it might change in a future language versions. – dephinera Nov 02 '20 at 15:22
  • @dephinera, I did not see anything like that before. Can you reference a link. I googled it and could not find anything. – Aymen Alsaadi Feb 16 '21 at 16:15
-1

The way I tend to to this (as well as a number of other libraries, such as pylons and paste, if my memory serves me correctly) is to separate the module name from the function/attribute name by using a ':' between them. See the following example:

'abc.def.ghi.jkl.myfile:mymethod'

This makes the import_from(path) function below a little easier to use.

def import_from(path):
    """
    Import an attribute, function or class from a module.
    :attr path: A path descriptor in the form of 'pkg.module.submodule:attribute'
    :type path: str
    """
    path_parts = path.split(':')
    if len(path_parts) < 2:
        raise ImportError("path must be in the form of pkg.module.submodule:attribute")
    module = __import__(path_parts[0], fromlist=path_parts[1])
    return getattr(module, path_parts[1])


if __name__=='__main__':
    func = import_from('a.b.c.d.myfile:mymethod')
    func()
Kris Hardy
  • 548
  • 4
  • 12
  • 1
    Why should anybdoy do this? This requires the caller to join module name and attribute name with a colon, and the function needs to split again at the colon. Why not simply use two parameters in the first place? – Sven Marnach Jan 09 '12 at 17:38
  • 1
    Often, a situation where this will come up is if you wire callbacks from a framework to your application using configuration files (.yaml, .ini, etc.). Then, you can specify which function the framework should call, etc., with a single string in your configuration file. – Kris Hardy Jan 12 '12 at 21:31
  • Well, yeah, you might want to choose this as a configuration file syntax. But how is this related to the OP's question? (And even if I had chosen this as my config file syntax, I'd prefer to have it parsed by my config file parser, not by random API functions.) – Sven Marnach Jan 12 '12 at 21:45