Python’s built-in “dunder” function __import__()
allows you to import a library by name. For example, you may want to import a library that was provided as a user input, so you may only have the string name of the library. For example, to import the NumPy library dynamically, you could run __import__('numpy')
.
In this tutorial, I’ll show you how to use the __import__()
function to customize the import behavior of your Python program—and import a module by (string) name. It’s a powerful function that should be used only by advanced coders. But the fact that you’re reading this already shows that you know what you’re doing. So, let’s move on to learn about this neat Python trick!
Note that it’s generally recommended to use the importlib
module if your only goal is to import a module by name.
Usage Example __import__()
The following code shows you how to use the built-in __import__() function to import the NumPy library and assign it to the name numpy
. It’s semantically equivalent to writing import numpy
.
numpy = __import__('numpy', globals(), locals(), [], 0) # Semantically equivalent to: import numpy a = numpy.array([1, 2, 3]) print(a * 2) # [2 4 6]
Syntax __import__()
__import__(name, globals=None, locals=None, fromlist=(), level=0)
Argument: | name | string. The name of the library to be imported. |
Argument: | globals=None | dictionary. Optional. A dictionary of name: objec t mappings that defines the names in the importing context. For example, it may be the result of the globals() function if you want to use your current global context. |
Argument: | locals=None | dictionary. Optional. A dictionary of name: object mappings that defines the names in the importing context. For example, it may be the result of the locals() function if you want to use your current local context. |
Argument: | fromlist=() | iterable. Optional. Allows you to import only specific objects rather than the whole module. |
Argument: | level=0 | integer. Optional. Use absolute or relative imports. -1 —> Default is -1 indicating that both absolute and relative imports will be attempted. 0 —> Only absolute imports x>0 —> Search x parent directories relative to module calling __import__() . |
Return Value | object | The imported module object. |
Why Is __import__() Discouraged?
If you use the import statement such as in import numpy
, it internally uses the __import__() built-in function as a semantically more powerful underlying implementation.
You can replace this behavior and customize it to your need by implementing the __import__() function yourself. However, you shouldn’t do this as it can cause dangerous side effects. For instance, the PEP 302 document explicitly discouraged doing this. You may ask: why?
Why is __import__()
discouraged according to PEP 302?
Overwriting the __import__()
function causes three problems:
- You need to reimplement the importing mechanism. But you may want to change only a small thing.
- It has complex semantics and responsibilities. It can inject new sources of bugs into your code.
- Even system modules in
sys.modules
call__import__()
. So, if you overwrite it, you’re tampering with well-tested global code.
Instead, PEP 302 advises to use simpler import hooks. You may ask:
What are import hooks?
They are a cleaner way to dynamically import libraries, given their name (and, possibly, path). Here are the relevant parts from PEP 302:
The protocol involves two objects: a finder and a loader. A finder object has a single method:
finder.find_module(fullname, path=None)
This method will be called with the fully qualified name of the module. If the finder is installed on sys.meta_path
, it will receive a second argument, which is None for a top-level module, or package.__path__
for submodules or subpackages. It should return a loader object if the module was found, or None
if it wasn’t. If find_module()
raises an exception, it will be propagated to the caller, aborting the import.
A loader object also has one method:
loader.load_module(fullname)
This method returns the loaded module or raises an exception, preferably ImportError
if an existing exception is not being propagated. If load_module()
is asked to load a module that it cannot, ImportError
is to be raised.
As it turns out, the library importlib.import_module()
implements what you need—and you should use it instead of the __import__()
function.
Summary
Python’s built-in “dunder” function __import__()
allows you to import a library by name, if you only have access to the library’s name as a string.
For example, you may want to import a library that was provided as a user input. For example, to import the NumPy library dynamically, you could run __import__('numpy')
.
numpy = __import__('numpy', globals(), locals(), [], 0) # Semantically equivalent to: import numpy a = numpy.array([1, 2, 3]) print(a * 2) # [2 4 6]
The __import__()
function is not recommended. If you need to import libraries by name, the recommended way is to use the importlib
library.
Do you want to boost your Python skills in a fun and easy-to-consume way? Consider the following resources and become a master coder!