In this article we will discuss the Circular Import Error that can occur when importing modules in Python, and how to solve it.
What is a Circular Import?
Circular imports in Python can be a tricky and confusing issue to deal with. A circular import occurs when two or more modules import each other, creating a looping cycle of imports that can lead to import errors. The below diagram illustrates what this looks like.
In this scenario, the Python interpreter will first encounter module A, which imports module B. However, since module B also imports module A, the interpreter will then try to import module A again. This creates a recursive loop where the interpreter keeps importing module A and module B indefinitely, without being able to complete the import process.
In this article, we will explore the various causes of circular imports and how to resolve them.
Circular Import Error
There are three major reasons for why this error can occur. The root cause for all these are the same, but the way in which they occur can vary a little. We will teach you how to identify these patterns, so that you can quickly resolve any circular import errors in your code.
We will start with the easiest problem to identify and solve. If you have given your Python file, the exact same name as the library you are importing, the Python interpreter will end up getting confused between the library which you actually mean to import, and your Python file (since they both have the sane name).
To fix this, all you need to do is change the name of your Python file to something else.
Here is an example you try out with the random library, where we also named our Python file “random.py”.
import random print(random.randint(0, 10))
This code will throw the following error.
Traceback (most recent call last): File "c:\Users\CodersLegacy\random.py", line 1, in <module> import random File "c:\Users\CodersLegacy\random.py", line 3, in <module> print(random.randint(0, 10)) AttributeError: partially initialized module 'random' has no attribute 'randint' (most likely due to a circular import)
Changing the file name to something like
random_code.py will make the code work.
Direct imports is the problem that we described right in the start. Let’s take a look at some actual code to better understand how this problem can occur.
Here we have code snippets, one for each Python file we have created. The first one (called moduleA.py) defines a function called
funcA. The second one (called moduleB.py) defines a function called
from moduleB import funcB def funcA(): print("I am module A") funcB()
from moduleA import funcA def funcB(): print("I am module B") funcA()
Running either of the above Python files will give us the error we got in the previous section.
The solution would be to put both functions in the same file, because their definitions depend on each other.
So something like this.
def funcB(): print("I am module B") funcA() def funcA(): print("I am module A") funcB()
No need for imports here.
It may sound a bit odd, but there really is no other way. You need to be smart about how you write your code. Pre-planning and drawing of an import graph (like the one in the start of this article) can help you identify whether you have any “cycles”.
Indirect imports are actually the same thing as direct imports. The only difference is that the chain of imports is longer. Instead of just two modules importing each other “directly” we have a chain of modules where one imports another, which imports another, and so on, until it eventually leads back to the first module. In other words, more than two modules are involved.
This can make it difficult to identify the source of the circular import, as it is not immediately obvious which modules are involved in the cycle.
Regardless, the solution here is the as the one we discussed for direct import, which would be to refactor your code.
This marks the end of the tutorial on “most likely due to a circular import” error and how to solve it. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the tutorial content can be asked in the comments section below.