What happens when using mutual or circular (cyclic) imports in Python?
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------
Music by Eric Matyas
https://www.soundimage.org
Track title: Secret Catacombs
--
Chapters
00:00 What Happens When Using Mutual Or Circular (Cyclic) Imports In Python?
00:38 Accepted Answer Score 369
01:37 Answer 2 Score 127
02:48 Answer 3 Score 476
04:23 Answer 4 Score 51
05:43 Thank you
--
Full question
https://stackoverflow.com/questions/7443...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #pythonimport #circulardependency #cyclicreference
#avk47
ANSWER 1
Score 476
If you do import foo (inside bar.py) and import bar (inside foo.py), it will work fine. By the time anything actually runs, both modules will be fully loaded and will have references to each other.
The problem is when instead you do from foo import abc (inside bar.py) and from bar import xyz (inside foo.py). Because now each module requires the other module to already be imported (so that the name we are importing exists) before it can be imported.
Examples of working circular imports in Python 2 and Python 3
The article When are Python circular imports fatal? gives four examples when circular imports are, for the reason explained above, nonfatal.
Top of module; no from; Python 2 only
# lib/foo.py                         # lib/bar.py
import bar                           import foo
def abc():                           def xyz():
    print(bar.xyz.__name__)              print(foo.abc.__name__)
Top of module; from ok; relative ok; Python 3 only
# lib/foo.py                         # lib/bar.py
from . import bar                    from . import foo
def abc():                           def xyz():
    print(bar.xyz.__name__)              print(abc.__name__)
Top of module; no from; no relative
# lib/foo.py                         # lib/bar.py
import lib.bar                       import lib.foo
def abc():                           def xyz():
    print(lib.bar.xyz.__name__)          print(lib.foo.abc.__name__)
Bottom of module; import attribute, not module; from okay
# lib/foo.py                         # lib/bar.py
def abc():                           def xyz():
    print(xyz.__name__)                  print(abc.__name__)
from .bar import xyz                 from .foo import abc
Top of function; from okay
# lib/foo.py                         # lib/bar.py
def abc():                           def xyz():
    from . import bar                    from . import foo
    print(bar.xyz.__name__)              print(foo.abc.__name__)
Additional examples
The article cited above does not discuss star imports.
ACCEPTED ANSWER
Score 369
There was a really good discussion on this over at comp.lang.python last year. It answers your question pretty thoroughly.
Imports are pretty straightforward really. Just remember the following:
'import' and 'from xxx import yyy' are executable statements. They execute when the running program reaches that line.
If a module is not in sys.modules, then an import creates the new module entry in sys.modules and then executes the code in the module. It does not return control to the calling module until the execution has completed.
If a module does exist in sys.modules then an import simply returns that module whether or not it has completed executing. That is the reason why cyclic imports may return modules which appear to be partly empty.
Finally, the executing script runs in a module named __main__, importing the script under its own name will create a new module unrelated to __main__.
Take that lot together and you shouldn't get any surprises when importing modules.
ANSWER 3
Score 127
Cyclic imports terminate, but you need to be careful not to use the cyclically-imported modules during module initialization.
Consider the following files:
a.py:
print "a in"
import sys
print "b imported: %s" % ("b" in sys.modules, )
import b
print "a out"
b.py:
print "b in"
import a
print "b out"
x = 3
If you execute a.py, you'll get the following:
$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
b out
a out
On the second import of b.py (in the second a in), the Python interpreter does not import b again, because it already exists in the module dict.
If you try to access b.x from a during module initialization, you will get an AttributeError.
Append the following line to a.py:
print b.x
Then, the output is:
$ python a.py
a in                    
b imported: False
b in
a in
b imported: True
a out
Traceback (most recent call last):
  File "a.py", line 4, in <module>
    import b
  File "/home/shlomme/tmp/x/b.py", line 2, in <module>
    import a
 File "/home/shlomme/tmp/x/a.py", line 7, in <module>
    print b.x
AttributeError: 'module' object has no attribute 'x'
This is because modules are executed on import and at the time b.x is accessed, the line x = 3 has not be executed yet, which will only happen after b out.
ANSWER 4
Score 51
As other answers describe this pattern is acceptable in python:
def dostuff(self):
     from foo import bar
     ...
Which will avoid the execution of the import statement when the file is imported by other modules. Only if there is a logical circular dependency, this will fail.
Most Circular Imports are not actually logical circular imports but rather raise ImportError errors, because of the way import() evaluates top level statements of the entire file when called.
These ImportErrors can almost always be avoided  if you positively want your imports on top:
Consider this circular import:
App A
# profiles/serializers.py
from images.serializers import SimplifiedImageSerializer
class SimplifiedProfileSerializer(serializers.Serializer):
    name = serializers.CharField()
class ProfileSerializer(SimplifiedProfileSerializer):
    recent_images = SimplifiedImageSerializer(many=True)
App B
# images/serializers.py
from profiles.serializers import SimplifiedProfileSerializer
class SimplifiedImageSerializer(serializers.Serializer):
    title = serializers.CharField()
class ImageSerializer(SimplifiedImageSerializer):
    profile = SimplifiedProfileSerializer()
From David Beazleys excellent talk Modules and Packages: Live and Let Die! - PyCon 2015, 1:54:00, here is a way to deal with circular imports in python:
try:
    from images.serializers import SimplifiedImageSerializer
except ImportError:
    import sys
    SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']
This tries to import SimplifiedImageSerializer and if ImportError is raised, because it already is imported, it will pull it from the importcache.
PS: You have to read this entire post in David Beazley's voice.