gotchapythonMajor
Circular import causes ImportError or partially initialized module
Viewed 0 times
circular importpartially initializedImportErrormodule cycle
Error Messages
Problem
Two modules importing each other cause ImportError: cannot import name 'X' from partially initialized module or AttributeError. Module A imports from B, B imports from A — one of them gets a partially loaded module.
Solution
Break the cycle with one of these approaches:
def my_func():
from module_b import something
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from module_b import MyClass
- Move the import inside the function that needs it (lazy import):
def my_func():
from module_b import something
- Restructure: extract shared code into a third module that both import.
- Use TYPE_CHECKING for type hints only:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from module_b import MyClass
Why
Python executes module code top-to-bottom on first import. If A imports B while A is still loading, B tries to import from A but A isn't fully initialized yet. The names B wants may not exist yet in A's namespace.
Gotchas
- from module import name fails more often than import module with circular deps
- __future__ annotations defers evaluation of type hints, avoiding runtime circular imports
- Moving imports to the bottom of the file sometimes works but is fragile
Code Snippets
Breaking circular imports
# Fix: lazy import inside function
def process():
from module_b import helper # imported when called, not at load time
return helper()
# Fix: TYPE_CHECKING guard for type hints
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from module_b import MyClassContext
When two or more Python modules import from each other
Revisions (0)
No revisions yet.