6

I would like to import a submodule without knowing its name beforehand,

>>> __import__("os.path")
<module 'os' from '/usr/lib/python3.3/os.py'>

Doesn't work as you might expect, returning os, not os.path.

I came up with this solution.

def import_submodule(mod, submod):
    ns = {}
    exec_str = "from %s import %s as submod" % (mod, submod)
    exec(exec_str, ns, ns)
    return ns["submod"]

This gives the result:

>>> import_submodule("os", "path")
<module 'posixpath' from '/usr/lib/python3.3/posixpath.py'>

However I would rather not use exec() because its rather bad practice and seems unnecessary when Pythons import mechanisms are available already through __import__, imp and importlib modules.

Is there a way in Python3.x to do this kind of import though a function call, rather then using exec() ?

10
  • possible duplicate of How to dynamically load a Python class Commented Sep 27, 2013 at 6:35
  • Note the name.split('.'), then loop to use getattr() to retrieve the 'subobject'; .path in your case. Commented Sep 27, 2013 at 6:36
  • 1
    Basing your examples on os.path might lead you on a wild goose chase, since it doesn't necessarily work like other modules Commented Sep 27, 2013 at 6:50
  • 2
    @ideasman42: __import__('parentmodule.submodule') does import submodule but returns parentmodule. Commented Sep 27, 2013 at 7:27
  • 1
    @MartijnPieters I believe this shouldn't be considered a duplicate since the OP is explicitly targetting python3.3 for which a better answer exist(i.e. importlib) which isn't cited in the answers to the other question. Marking this as a duplicate might mean that people will still use other home-made solutions instead of the new import machinery. On current versions of python you almost never need to call __import__ directly. Commented Sep 27, 2013 at 14:56

3 Answers 3

5

Use importlib.import_module:

>>> import importlib
>>> importlib.import_module('os.path')
<module 'posixpath' from '/usr/lib/python2.7/posixpath.pyc'>

This should work in python2.7+ and 3.1+.

Sign up to request clarification or add additional context in comments.

Comments

3

Note that if you want do: from A import B as C as a function call, importlib.import_module won't always work, since B may not be a module.

Heres a function which uses importlib and getattr.

def my_import_from(mod_name, var_name):
    import importlib
    mod = importlib.import_module(mod_name)
    var = getattr(mod, var_name)
    return var

So this:

from os.path import dirname as var

Can be replaced with this:

var = my_import_from("os.path", "dirname")

Which avoids exec and allows both submodules and any variables defined in the module.

Since my question explicitly says importing a submodule, the answer from @Bakuriu is correct, however including this for completeness and it may help others who run into the same problem.

Comments

0

Import both parts

As @Marius pointed out in the comment section, what appears as a submodule is not always a submodule. This is the case with os.path and I encountered the same with lxml.etree. The trick is to import both parts, i.e. both os and os.path. Here is what worked for me for sets of modules:

# PyPI imports
import pkg_resources, subprocess, sys

modules   = {'lxml.etree', 'pandas', 'screeninfo'}
required  = {m.split('.')[0] for m in modules}
installed = {pkg.key for pkg in pkg_resources.working_set}
missing   = required - installed

if missing:
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', '--upgrade', 'pip'])
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', *missing])

for module in set.union(required, modules):
    globals()[module] = __import__(module)

Tests:

print(pandas.__version__)
print(lxml.etree.LXML_VERSION)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.