views:

1485

answers:

5

What will happen if two modules import each other?

To generalize the problem, what about the cyclic imports in Python.

+18  A: 

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.

Shane C. Mason
This is fairly a great answer.
Xolve
+4  A: 

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.

Edit: 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.

Torsten Marek
You should provide information on "be careful not to use the cyclically-imported modules during module initialization".
S.Lott
A: 

If you do "import foo" inside bar and "import bar" inside foo, 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" and "from bar import xyz". Because now each module requires the other module to already be compiled (so that the name we are importing exists) before it can be compiled.

A: 

I got an example here that struck me!

foo.py

import bar

class GO(object):
    g = 10

bar.py

from foo import gX

o = gX()

main.py

import foo
import bar

print "all done"

At the command line: $ python main.py

*Traceback (most recent call last):
  File "m.py", line 1, in <module>
    import foo
  File "/home/xolve/foo.py", line 1, in <module>
    import bar
  File "/home/xolve/bar.py", line 1, in <module>
    from foo import gX
ImportError: cannot import name gX*
Xolve
How did you fix this? I'm trying to understand circular import to fix a problem of my own that looks *very* similar to what you're doing...
Chris089
Errm... I think I fixed my problem with this incredibly ugly hack. {{{if not 'foo.bar' in sys.modules: from foo import barelse: bar = sys.modules['foo.bar']}}}Personally, I think circular imports are a HUGE warning sign on bad code design...
Chris089
A: 

A good answer was already provided, and it may be obvious, but it is generally better to avoid circular imports. For once, it make debugging quite difficult if you have some import related problems, and it is not often needed in my experience.

David Cournapeau