3

I'm trying to dynamically load modules as explained here.

I have written a script that requires some modules that may not be installed by default on some systems (such as requests). The script code assumes that a regular import has been done (it uses requests.get).

If I use the code in the link above, to import requests I would have to use:

requests=importlib.import_module('requests')

But this leads to a lot of code duplication since I have several modules. I can't use that in a loop since the variable name must change with the imported module.

I have found that I can use:

for m in list_of_modules:
    locals()[m]=importlib.import_module(m)

And everything happens as if I had done regular import's. (of course the real code catches exceptions...).

So the question is how valid/risky this is? Too good to be true or not? (Python 2.7 if that makes a difference)

xenoid
  • 8,396
  • 3
  • 23
  • 49
  • 1
    Any reason why you're using `locals` instead of `globals`? – Aran-Fey Jul 24 '18 at 12:58
  • Also, note this [answer](https://stackoverflow.com/a/8028743/7692463) in your linked thread, which is exactly what you propose. It seems like the community kinda accepted it (13 upvotes - 0 downvote) – scharette Jul 24 '18 at 13:05
  • This is a horrible idea; `locals()` is not guaranteed to be writable. The proper way to handle an import of an optionally-installed module is to do it in a `try`...`except ImportError:` block. – jasonharper Jul 24 '18 at 13:05

1 Answers1

2

It is explicitely invalid. Doc of Python 2.7.15 says of locals() function:

The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.

locals() is a way for the program to know the list of variables in a function block. It is not a way to create local variables.

If you really need something like that, you can either use a local map, rely on the sys.modules map which is updated by import_module, or update the globals() map. Anyway, once a module was loaded, it exists (through the sys.module map) for the whole program, so it does not really make sense to store its reference in a local symbol table.

So if you really need to import a dynamically builded list of modules, I would do:

for m in list_of_modules:
    globals()[m]=importlib.import_module(m)
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252