Possible Duplicate:
Cyclic module dependencies and relative imports in Python
Consider the following example of cyclic imports in python:
main.py:
from pkg import foo
pkg/__init.py__:
# empty
pkg/foo.py:
from pkg import bar
pkg/bar.py:
from pkg import foo
Running main.py will cause an exception:
Traceback (most recent call last):
File "/path/to/main.py", line 1, in <module>
from pkg import foo
File "/path/to/pkg/foo.py", line 1, in <module>
from pkg import bar
File "/path/to/pkg/bar.py", line 1, in <module>
from pkg import foo
ImportError: cannot import name foo
Changing bar.py to:
# from pkg import foo
import pkg.foo
will make the example work.
Why does this happen? Shouldn’t *import package.module” and “from package import module” be equivalent (except for the extra name binding in the latter)?
First of all you have to understand that:
The
sys.modulesvariable play the role of a cache in the import mechanize which mean that if we import a module the first time, an entry containing the name of this module is added tosys.modules, so that when we try to import this same module next time, we will only get the already cached module fromsys.modulesand we will not execute the module again.The difference between
import pkg.fooandfrom pkg import foois that the second is equivalent too:import pkg.foofollowed bygetattr(pkg, 'foo'). (check my answer here for more detail)Now what happen in your first example is the following:
1- In
main.py: we start by executing the linefrom pkg import foo, so first the entrypkg.foois added tosys.modules(i.e.'pkg.foo' in sys.modules == True) than we try to importfoo.2- In
foo.py: While importingfoowe end up executing this line:from pkg import barand again the entrypkg.baris added tosys.modules; and than we start importingbar, what is important to note here is that we are still executingfoo.py, so we are kind off still executing this linefrom pkg import foofrommain.py.3- In
bar.py: while now importingbar.pywe end up executing the line:from pkg import foo, but remember we have already an entry insys.modulesforpkg.foowhich mean that executingfoo.pywill be skipped and the import mechanize will get us instead thesys.modules['pkg.foo']entry, and now we will excutegetattr(pkg, 'foo')as explained above, but remember ‘pkg.foo’ didn’t finish importing; which mean that there is no attributefoowhich explain the error.Now if you put in
bar.pyonlyimport pkg.foothis will not have the line that cause us the problem last time which is:getattr(pkg, 'foo').HTH,