As part of a language, Python obviously has import
statements. They allow us to divide the code into different modules and packages:
What is lesser known fact is that it also has an __import__
function. This function retains all functionality of the import
statement, but has some additional features and slightly different use cases. With it, for example, you can import a module whose name you only know at “runtime”:
This comes handy in various types of general dispatchers, factory functions, plugin systems, and so forth. Returned from __import__
function is always a module object (even in cases when fromlist
argument is used), so often a getattr
is needed to extract a specific symbol from it.
Quite surprisingly, I have discovered that __import__
function may very well be useful also when you do know the desired module name. Reason is that import
statement is sometimes unwieldy. It has similar problem as global variables (i.e. global
statements) and inner function def
initions (as opposed to lambda
s): it makes the code stretch unnecessarily in the vertical dimension.
This can be considered a waste if you only need to access one specific thing from one specific module. Using __import__
function, you can golf the import and the usage into a single statement. Here’s an example, coming straight from my own project recursely:
Incidentally, the other uses of literal __import__
described can be conveniently replaced thanks to that small library :)
Another issue with import
statement is that it introduces symbols into the global (or local) namespace. Most of the time, this is precisely what we want. Occasionally, though, a sole fact of loading the module is enough.
A canonical example of the latter case is web application with request handlers scattered between different Python files, or even packages. All those files have to be imported if the handlers are to be added to framework’s routing table; but beyond that, we have no business with them.
As a result, the import
statement(s):
introduces an unused symbol – here, it is handlers
. Many linting tools will be eager to point this fact out, which is not really that helpful. There is sometimes an option to disable the warning on per line basis, but some checkers (e.g. pep8.py) don’t offer this functionality.
Universal solution? Use __import__
function, of course:
The module is still loaded just fine, but since we’re ignoring the return value, no stray variables are created. As a added bonus, the __import__
call also looks very different, signifying its special purpose.
Actually, there is one more benefit of this trick, also coming from fooling-the-tools department. Many Python IDEs, like Eclipse/Pydev, are able to automatically insert necessary imports and organize them in groups, effectively providing a neat, Java-like experience. What is not so neat is that they often insist on putting every import
statement somewhere near the beginning of the file. preceding any other definition, variable, class or function.
In a scenario described above, this behavior may actually cause problems. When the handlers’ module gets imported, it may need to refer back to the application object; this is exactly the case in the Flask framework, for example. If that object happens to be defined in the module importing handlers
, we’ll have a circular import error because the application object has not yet been defined. It would have been defined, however, if the statement:
hasn’t been touched by the IDE when it wanted to be helpful and organize our imports. All imports, as it turns out.
Fortunately, mechanisms like that tend to be easy to fool. Per answers to StackOverflow question I’ve once asked, it is a matter breaking the textual pattern that the algorithm searches our code for. As you may have guessed by now, one of the ways of achieving that goal is to shed the import
statement in favor of __import__
function.