I'm puzzled by how circular imports are handled in Python. I've tried to distill a minimal question and I don't think this exact variant was asked before. Basically, I'm seeing a difference between
import lib.foo
and
import lib.foo as f
when I have a circular dependency between lib.foo
and lib.bar
. I had expected that both would work the same: the (possibly half-initialized) module would be found in sys.modules
and put into the local namespace. (From testing I noticed that import lib.foo
really puts lib
into the local namespace — okay, with that syntax I'll do lib.foo.something
anyway.)
However, if lib.foo
is already in sys.modules
, then import lib.foo as f
tries to access foo
as an attribute on lib
and raises AttributeError. Why does the behavior (seemingly) depend on the presence in sys.modules
?
Also, where is this behavior documented? I don't feel that the Python import
statement reference explains this behavior, or at least I couldn't extract it :-)
All in all I'm trying to change a code base to use the oft recommended style where you import modules, not symbols in the modules:
from project.package import moduleA
from project.package import moduleB
But that fails when there are circular imports between the two modules. I had expected it to work as long as the top-level definitions in the two modules don't depend on each other (e.g., no subclass in moduleB
with a base class in moduleA
).
Test script:
#!/bin/sh
rm -r lib; mkdir lib
touch lib/__init__.py
cat > lib/foo.py <<EOF
# lib.foo module
print '{ foo'
#import lib.bar # works
import lib.bar as b # also works
#from lib import bar # also works
print 'foo }'
EOF
cat > lib/bar.py <<EOF
# lib.bar module
print '{ bar'
#import lib.foo # works
import lib.foo as f # AttributeError: 'module' object has no attribute 'foo'
#from lib import foo # ImportError: cannot import name foo
print 'bar }'
EOF
python -c 'import lib.foo'