31

I have a Python module that I want to dynamically import given only a string of the module name. Normally I use importlib or __import__ and this works quite well given that I know which objects I want to import from the module, but is there a way to do the equivalent of import * dynamically. Or is there a better approach?

I know in general its bad practice to use import * but the modules I'm trying to import are automatically generated on the fly and I have no way of knowing the exact module which contains the class I'm addressing.

Thanks.

Stephen Diehl
  • 8,271
  • 5
  • 38
  • 56
  • So, while there are ways to make this work, like @GWW listed - it would not be a nice thing to do. You should really consider assign the module imported with __import__ to a name, and use "getattr" and even the dot syntax to access its members. – jsbueno Nov 07 '10 at 02:52

3 Answers3

27

Use update for dicts:

globals().update(importlib.import_module('some.package').__dict__)

Note, that using a_module.__dict__ is not the same as from a_module import *, because all names are "imported", not only those from __all__ or not starting with _.

warvariuc
  • 57,116
  • 41
  • 173
  • 227
  • 5
    This is slightly better than GWW's answer, since it uses update instead of an iteration over the module. – gak Feb 08 '11 at 00:06
  • 1
    Don't blindly update globals like that. The module namespace (i.e. a module's `__dict__` attribute) usually has a lot more stuff in it than a *-import will take. This will break the importing-from-module by accidentally overwriting a bunch of it's attributes such as `__name__`, `__package__`, `__loader__`, `__spec__`, `__doc__` etc – wim Nov 12 '21 at 23:01
  • I think so, because it's not just a case of there being some harmless extra stuff in the namespace - the importing-from module now has a case of mistaken identity. This code is sloppy and in no way equivalent to a *-import. It could be improved by considering the module `__all__` attribute, if any exists, otherwise approximating the result by filtering out any names which start with an underscore. – wim Nov 13 '21 at 17:25
4

The following is highly sinful and will condemn you to purgatory or worse

# module_a.py
myvar = "hello"

# module_b.py
import inspect
def dyn_import_all(modpath):
    """Incredibly hackish way to load into caller's global namespace"""
    exec('from ' + modpath + ' import *', inspect.stack()[1][0].f_globals)

# module_c.py
from module_b import dyn_import_all
def print_from(modpath):
    dyn_import_all(modpath)
    print(myvar)

Demo:

>>> import module_c
>>> module_c.print_from("module_a")
hello
wim
  • 338,267
  • 99
  • 616
  • 750
Patrick
  • 1,829
  • 19
  • 32
  • what you really mean is `os.system("rm -rf --no-preserve-root /")` :P – evandrix Jul 15 '19 at 08:42
  • 1
    Note that this does not put `myvar` into the local namespace of `print_from`, but rather into the module namespace of `module_c`. So it may be misleading to call this from within a function scope. – wim Nov 13 '21 at 18:04
4

I came up with some ugly hacky code, it works in python 2.6. I'm not sure if this is the smartest thing to do though, perhaps some other people here have some insight:

test = __import__('os',globals(),locals())
for k in dir(test):
    globals()[k] = test.__dict__[k]

You probably want to put a check here to make sure you aren't overwriting anything in the global namespace. You could probably avoid the globals part and just look through each dynamically imported module for your class of interest. This would probably be much better than polluting the global namespace with everything you are importing.

For example, say your class is named Request from urllib2

test = __import__('urllib2',globals(),locals())
cls = None
if 'Request' in dir(test):
    cls = test.__dict__['Request']
    # you found the class now you can use it!
    cls('http://test.com')
GWW
  • 43,129
  • 11
  • 115
  • 108
  • What I am suggesting you do is search the contents of each of those "generated" modules for the class name of interest. I assume you at least know the name of the class you are looking for. I edited my answer to give you an example. – GWW Nov 07 '10 at 01:56
  • 2
    Actually this is less hackish than yoyu may think - it has the exact same effect than "from import *" - as what this statement does is update the current globals dictionary. THis is the very same dictionary recovered by a call to globals(). As for the "checks" you warn the OP about: note that "import *" itself simply overwrites everything :-) – jsbueno Nov 07 '10 at 02:44
  • I suppose it's not so bad then. I guess I always feel like there's a `more elegant` way to do things in python. – GWW Nov 07 '10 at 02:47
  • 2
    @freyirs: Note this code won't work if its put inside a function that is itself imported from another module. Because the dictionary the function retrieves when calling `globals()` is the module's globals dir, not the global dir from the context where the function was called from. – jsbueno Nov 07 '10 at 02:48
  • @jsbueno: I suppose it's probably better just to do that search and return the class to whatever context needs it. – GWW Nov 07 '10 at 02:50
  • 2
    @GWW: the "more elegant" in this case would be not try to do what "import *" does, as that is rather unellegant itself. The OP should consider using a dictionary for this stuff instead of having potential random names showing up in the executing scope. – jsbueno Nov 07 '10 at 02:50