How to Solve Circular Dependencies in Python

Marco Maigua
The Blockchain Artist
3 min readJan 4, 2023

Circular dependencies can be a major headache for developers working with Python. They occur when two or more modules depend on each other, creating a cycle that can cause issues when trying to import the modules. In this article, we’ll discuss what circular dependencies are and how to solve them in Python.

What are circular dependencies?

Circular dependencies occur when two or more modules depend on each other, resulting in a cycle. For example, consider the following code, which has a circular dependency between module A and B:

# module A
import B

def foo():
return B.bar()

# module B
import A

def bar():
return A.foo()

This code will cause issues when trying to import either A or B, as the modules will import each other in an infinite loop.

How to solve circular dependencies in Python

There are a few different ways to solve circular dependencies in Python. One approach is to refactor the code to break the cycle by moving some of the functionality from one module to another, or by creating a new module to hold the shared functionality.

For example, here’s how you can break the circular dependency between A and B from the previous example:

# module A
import C

def foo():
return C.shared_func()

# module B
import C

def bar():
return C.shared_func()

# module C
def shared_func():
# implementation of shared functionality

This refactoring breaks the cycle by moving the shared functionality into a separate module that is imported by both A and B.

Another solution is to use import hooks to modify the import process and allow the modules to be imported in a specific order. However, this can be complex and may not be suitable for all situations.

How to solve circular dependencies with importlib

The importlib module provides tools for modifying the import process, including the import_module function, which can be used to import a module from a string. This can be useful for solving circular dependencies, as it allows you to import a module without specifying the module name directly.

To use importlib to solve a circular dependency, you can modify the import statements to use import_module instead of the regular import statement. For example, here's how you can modify the code from the previous example to avoid the circular dependency:

# module A
from importlib import import_module

B = import_module('B')

def foo():
return B.bar()

# module B
from importlib import import_module

A = import_module('A')

def bar():
return A.foo()

This code uses import_module to import B and A from their respective module names, rather than using the import statement. This allows the modules to be imported without creating a circular dependency.

It’s generally a good practice to avoid circular dependencies whenever possible, as they can make the code more difficult to understand and maintain. To avoid circular dependencies, make sure each module has a clear, well-defined purpose, and only import the modules that are absolutely necessary. You can also use relative imports when possible, rather than absolute imports.

Conclusion

Circular dependencies can be a major issue in Python, but with a little planning and refactoring, they can be easy to solve. By breaking the cycle and moving shared functionality into separate modules, or by using import hooks to modify the import process, you can avoid circular dependencies and keep your code running smoothly.

Here are a few book recommendations for learning more about solving circular dependencies in Python:

  1. “Clean Code: A Handbook of Agile Software Craftsmanship” by Robert C. Martin: This book provides guidelines for writing clean, maintainable code, and includes a section on avoiding circular dependencies.
  2. “Code Complete: A Practical Handbook of Software Construction, Second Edition” by Steve McConnell: This comprehensive guide to software construction covers a wide range of topics, including how to avoid circular dependencies.
  3. “Refactoring: Improving the Design of Existing Code” by Martin Fowler: This book covers a variety of refactoring techniques, including how to break circular dependencies and improve the design of existing code.

--

--