Some text some message..
Back 🌀 Circular Import in Python 30 Aug, 2025

🔹 What is a Circular Import?

A circular import happens when two or more modules depend on each other directly or indirectly during the import process.

In simple words:

  • Module A imports Module B

  • Module B imports Module A

  • This creates a loop (cycle) → Python gets stuck or gives errors.


🔹 How Python Imports Work (Important to Understand!)

When Python imports a module:

  1. It creates a module object and places it in sys.modules.

  2. It executes the code inside the module.

  3. If another import happens inside it, Python checks sys.modules:

    • If module exists but is not yet fully executed, Python may give partially initialized module errors.

👉 That’s why circular imports often raise:

ImportError: cannot import name 'X' from partially initialized module

🔹 Example of Circular Import

File: a.py

print("Loading a.py")
import b   # a.py imports b.py

def func_a():
    print("Function A")

File: b.py

print("Loading b.py")
import a   # b.py imports a.py

def func_b():
    print("Function B")

File: main.py

import a

✅ What happens:

  1. Python loads a.py → sees import b.

  2. It starts loading b.py → sees import a.

  3. But a is already being loaded, so Python provides a partially initialized a.

  4. If you try to use something in a that isn’t yet defined, you get an error.


🔹 Errors You Might See

  1. Partially initialized module:

    ImportError: cannot import name 'func_a' from partially initialized module 'a'
    
  2. Sometimes works but gives unexpected behavior because of incomplete definitions.


🔹 Ways to Solve Circular Imports

1. Reorganize Imports (Best Practice)
Move shared functions/classes into a third module that both can import.

Example:

  • a.py and b.py both import from common.py.

2. Local Imports (inside functions)
Instead of top-level imports, import only when needed.

# b.py
def func_b():
    from a import func_a
    func_a()
    print("Function B")

3. Use import module instead of from module import X
This avoids early evaluation of attributes.

# Instead of
from a import func_a

# Do this
import a

def func_b():
    a.func_a()

4. Refactor Code Structure
Sometimes circular imports mean the code design is tightly coupled.
Breaking it into layers (utilities, services, models, controllers, etc.) helps.


🔹 When Circular Import is Okay

  • If modules don’t access each other’s values during import, Python can resolve it.

  • Example: both modules just import each other but use them only after program startup.


🔹 Quick Analogy

Think of circular import like two people trying to shake hands at the exact same time.
Each one is waiting for the other → results in a deadlock or incomplete action.


Summary:

  • Circular import = mutual dependency between modules.

  • It causes ImportError or unexpected behavior.

  • Fix by restructuring code, using local imports, or splitting common logic into a new module.