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
definitions (as opposed to
lambdas): 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
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