Import a Python module dynamically by name or path
Use importlib for runtime module names, load a trusted file with a checked module spec, and understand discovery, caching, and reload limits.
Use importlib.import_module() when the module's name is known only at runtime:
import importlib
itertools = importlib.import_module("itertools")
path_module = importlib.import_module("os.path")
print(path_module.basename("/tmp/example.txt")) # example.txt
The returned object is the requested module. Normal import search paths and caching still apply, and importing a module executes its initialization code.
Check whether a module can be found
import importlib.util
spec = importlib.util.find_spec("itertools")
print(spec is not None)
A spec indicates that the import machinery can locate a module; it does not prove that executing the module will succeed. For a dotted name, find_spec() can import the parent package, so it is not a side-effect-free check in every case.
Load a trusted Python file
import importlib.util
import sys
from pathlib import Path
def load_module(name, path):
if name in sys.modules:
raise ValueError(f"Module name already loaded: {name}")
spec = importlib.util.spec_from_file_location(name, Path(path))
if spec is None or spec.loader is None:
raise ImportError(f"No loader for {path}")
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
try:
spec.loader.exec_module(module)
except BaseException:
sys.modules.pop(name, None)
raise
return module
# Use a trusted existing source file:
# module = load_module("my_plugin", "/path/to/my_plugin.py")
Registering the module before execution supports code that looks itself up during initialization. The cleanup removes that registration if execution fails; it cannot undo arbitrary side effects or every dependency imported by the file. The broad exception catch is used only for cleanup and immediately re-raises.
File-path loading does not automatically create the package context needed by relative imports. For packaged plugins, normal named imports are usually easier to maintain. Never load an untrusted file as if importing were a sandbox.
Discover modules in a plugin package
When plugins is a trusted importable package whose plugin modules expose register():
import importlib
import pkgutil
import plugins
for _, name, _ in pkgutil.iter_modules(plugins.__path__):
module = importlib.import_module(f"plugins.{name}")
module.register()
This discovers immediate children, including subpackages; it is not a recursive search through every nested file. Decide whether a failed plugin should stop startup or be logged and skipped, and validate its expected interface.
FAQ
Why not use import()? With its default arguments, __import__("package.module") returns the top-level package. import_module() returns the requested module and is easier to use here.
Can I reload it? importlib.reload() re-executes a discoverable module, but existing references, imported names, and class instances do not all change automatically. A manually loaded file may lack a discoverable spec for reload. Treat reload as an explicit development mechanism, not a complete production update system.
Which failures should I catch? ImportError includes missing-module failures, but module initialization can also raise unrelated exceptions. Preserve the original error and traceback so a broken dependency is not mistaken for a missing plugin.
References
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan