ImportError: cannot import name from partially initialized module in Python
This error occurs when two modules import each other circularly. Refactor shared dependencies into a separate module or defer imports inside functions.
Root Cause Analysis
This error occurs when Python tries to import an attribute from a module during execution, but the module is partially initialized because of a circular dependency cycle between importing files.
Cause 1: Circular Dependencies (A imports B, B imports A)
When module_a.py executes from module_b import helper, Python pauses initializing module_a and begins evaluating module_b. If module_b.py contains from module_a import Config, Python looks for Config inside module_a, but module_a has not yet finished executing, raising ImportError: cannot import name 'Config' from partially initialized module 'module_a' (most likely due to a circular import).
Cause 2: Local File Shadowing Standard Library Modules
Naming a script json.py, typing.py, or csv.py causes standard libraries or third-party packages to import your local script during startup, triggering unexpected partial initialization crashes.
Cause 3: Top-Level Type Hint Imports
Importing classes at the top level solely for type annotations frequently introduces circular cycles between models and services.
Reproduction Code (MCVE)
import sys
# Simulate circular import error
raise ImportError("cannot import name 'User' from partially initialized module 'models' (most likely due to a circular import)")
Solution 1: Refactor Shared Classes into a Dedicated Module
Extract common data structures, interfaces, or configurations into an independent foundational module (e.g. types.py or models.py) imported by both consumers.
# Shared models module definition
class User:
def __init__(self, username: str):
self.username = username
class AuthService:
def authenticate(self, user: User) -> bool:
return user.username == 'admin'
u = User('admin')
auth = AuthService()
print(f'Auth result: {auth.authenticate(u)}')
Solution 2: Use Deferred (In-Function) Imports or TYPE_CHECKING
Move imports that are only needed at runtime inside the functions that use them, or guard type-only imports with if typing.TYPE_CHECKING:.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
# Only imported by static type checkers (mypy/pyright), not at runtime
pass
def execute_task():
# Deferred import executes only when function is called
import math
return math.sqrt(144)
print(f'Calculated square root: {execute_task()}')
Common Mistakes & Edge Cases
1. from module import item vs import module
Using import module_a binds the module object itself, which can tolerate circularity if attributes are accessed later at runtime. In contrast, from module_a import item requires the specific attribute to exist immediately at import time.
2. Contrasting ImportError vs AttributeError
In Python 2 and early Python 3, circular imports raised AttributeError: 'module' object has no attribute 'x'. Modern Python explicitly identifies the cycle as ImportError: cannot import name ... from partially initialized module.
3. Circular Imports in init.py
Exposing submodule functions in package __init__.py while submodules import from __init__.py is a common architectural pitfall. Keep __init__.py clean.
4. Note de Reproductibilité Environnementale
Le comportement des commandes système et des résolutions de paquets dépend fortement de votre système d'exploitation (Windows, macOS, Linux), de l'architecture processeur (x86_64 vs ARM64) et de la configuration des permissions locales. Adaptez les chemins et les permissions selon votre environnement d'exécution spécifique.