This question already has an answer here:
- Circular import dependency in Python 5 answers
I know the issue of circular imports in python has come up many times before and I have read these discussions. The comment that is made repeatedly in these discussions is that a circular import is a sign of a bad design and the code should be reorganised to avoid the circular import.
Could someone tell me how to avoid a circular import in this situation?: I have two classes and I want each class to have a constructor (method) which takes an instance of the other class and returns an instance of the class.
More specifically, one class is mutable and one is immutable. The immutable class is needed for hashing, comparing and so on. The mutable class is needed to do things too. This is similar to sets and frozensets or to lists and tuples.
I could put both class definitions in the same module. Are there any other suggestions?
A toy example would be class A which has an attribute which is a list and class B which has an attribute which is a tuple. Then class A has a method which takes an instance of class B and returns an instance of class A (by converting the tuple to a list) and similarly class B has a method which takes an instance of class A and returns an instance of class B (by converting the list to a tuple).
Only import the module, don't import from the module:
Consider
a.py
:and
b.py
:This works perfectly fine.
We do a combination of absolute imports and functions for better reading and shorter access strings.
main/sub/a.py
main/sub/b.py
Consider the following example python package where
a.py
andb.py
depend on each other:There are several ways to import a module in python
Unfortunately, only the 1st and 4th options actually work when you have circular dependencies (the rest all raise
ImportError
orAttributeError
). In general, you shouldn't be using the 4th syntax, since it only works in python2 and runs the risk of clashing with other 3rd party modules. So really, only the first syntax is guaranteed to work. However, you still have several options when dealing with circular dependencies.Use Absolute Imports
Just use the first import syntax above. The downside to this method is that the import names can get super long for large packages.
In
a.py
In
b.py
Defer import until later
I've seen this method used in lots of packages, but it still feels hacky to me, and I dislike that I can't look at the top of a module and see all its dependencies, I have to go searching through all the functions as well.
In
a.py
In
b.py
Put all imports in a central module
This also works, but has the same problem as the first method, where all the package and submodule calls get super long. It also has two major flaws -- it forces all the submodules to be imported, even if you're only using one or two, and you still can't look at any of the submodules and quickly see their dependencies at the top, you have to go sifting through functions.
In
__init__.py
In
a.py
In
b.py
So those are your options (and they all kinda suck IMO). Frankly, this seems to be a glaring bug in the python import machinery, but thats just my opinion.