__import__() in Python 2026: How It Works, Security Risks & Modern Alternatives (importlib)
The __import__() built-in function is one of Python's most powerful — and most dangerous — tools for dynamic module loading. In 2026, even though it's still part of the language, almost every style guide, security audit, and modern codebase recommends avoiding it in favor of importlib.import_module() or importlib.util helpers. Why? Because __import__ is low-level, hard to secure, and error-prone — especially in plugins, configuration-driven systems, or code that loads modules from untrusted sources.
I've seen __import__ cause real damage in production: remote code execution in plugin systems, import bombs, and subtle bugs from incorrect globals/locals handling. This March 2026 guide explains exactly how __import__ works, when you might still encounter it, its major security & maintainability risks, and the clean, safe alternatives you should use instead.
TL;DR — Key Takeaways 2026
- __import__ is a low-level built-in — not meant for everyday use
- Main risks: security holes (arbitrary code exec), confusing semantics, hard debugging
- Modern replacement:
importlib.import_module()(simple & safe) orimportlib.util.module_from_spec()(advanced control) - 2026 recommendation: Never use __import__ in new code unless you're implementing a very specific import hook or compatibility layer
- Security rule: If you must dynamically import from user input → use restricted environments (restrictedpython, subprocess, sandboxing)
1. How __import__() Actually Works (2026 Reality)
The signature hasn't changed since Python 2:
__import__(name, globals=None, locals=None, fromlist=(), level=0)
- name: module name (str) — can be dotted ("os.path")
- globals/locals: used to determine relative import context (usually __import__('module', globals(), locals()))
- fromlist: list of names to import with "from module import ..." syntax
- level: 0 = absolute, positive = relative to current package
Common (but dangerous) usage patterns still seen in 2026:
# Old plugin system pattern — HIGHLY discouraged
plugin = __import__('plugins.' + plugin_name, globals(), locals(), ['run'])
# Relative import emulation (rarely needed)
from . import sibling
# equivalent to:
sibling = __import__('sibling', globals(), locals(), [], 1)
2. Security & Maintainability Risks in 2026
| Risk | Description | Severity 2026 | Modern Fix |
|---|---|---|---|
| Arbitrary code execution | __import__('malicious') executes top-level code | Critical | Use importlib + validation / sandbox |
| Import bombs | Module with huge __init__ can DoS your process | High | Avoid dynamic import from untrusted input |
| Confusing globals/locals | Wrong context → wrong relative imports | Medium | Never pass globals/locals manually |
| Hard to audit | Static analyzers miss dynamic imports | High | Use importlib.import_module() |
| Deprecated feel | PEP 302 / PEP 451 moved import machinery to importlib | Low | Switch to importlib for future-proof code |
3. Modern & Safe Alternatives (Use These in 2026)
Simple dynamic import — importlib.import_module()
import importlib
# Safe equivalent to __import__('os.path')
os_path = importlib.import_module('os.path')
# Dynamic plugin name (validate first!)
plugin_name = 'safe_plugin' # never trust user input directly
plugin = importlib.import_module(f'myapp.plugins.{plugin_name}')
plugin.run()
Advanced: full control with module_from_spec
import importlib.util
import sys
def safe_import(name):
spec = importlib.util.find_spec(name)
if spec is None:
raise ImportError(f"No module named {name}")
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module # cache it
spec.loader.exec_module(module) # execute
return module
# Usage
my_module = safe_import('myapp.utils.helpers')
4. When You Might Still See __import__ in 2026
- Very old libraries (pre-2015) still using it
- Custom import hooks / meta_path finders (PEP 302/451)
- Compatibility shims (supporting Python 2.7 code)
- Generated code or eval-like environments (Django templates, Jupyter extensions)
Rule of thumb: If you're writing new code in 2026 — never use __import__ unless you're implementing import machinery itself.
Conclusion — __import__ in 2026: Legacy, Not Recommended
__import__ is a relic of Python's early import system — powerful but unsafe and confusing. In 2026, use importlib.import_module() for simple dynamic imports and importlib.util.module_from_spec() when you need full control. If you're loading modules from user input, plugins, or configuration — always validate names, use sandboxing (restrictedpython, subprocess), or better yet, redesign to avoid dynamic imports entirely.
Next steps:
- Search your codebase for __import__ and replace with importlib
- Related articles: Efficient Python Code 2026 • Python Built-ins Overview 2026