circular imports

"Martin v. Löwis" martin at v.loewis.de
Fri May 20 15:35:42 EDT 2005


qhfgva at gmail.com wrote:
> All of the __init__.py files are empty and I don't know of any
> overlapping of names.  Like I said this is code that works fine, I'm
> just trying to clean up some things as I go. 

I see. The problem is that a module in a package is entered into
the parent package only after the import is complete. The sequence
goes like this:

create module aaa.z2
add aaa.z2 to sys.modules
run content aaa.z2
add aaa.z2 to aaa

This procedure is needed for rollback in case of exceptions: if
the code in aaa.z2 fails, the traces of the module object must
be discarded. This currently only undoes the sys.modules change.

Now, with circular imports, you get

create module aaa.z2
add aaa.z2 to sys.modules
run aaa.z2
  from aaa import z1
  is "aaa.z1" already in sys.modules? no - load it
     create aaa.z1
     add aaa.z1 to sys.modules
     run aaa.z1
       from aaa import z2
       is aaa.z2 already in sys.modules? yes - skip loading it
       fetch z2 from aaa -> NameError, aaa has no z2 yet

The problem here is "import from"; this doesn't work with circular
imports too well. For plain "import", circularity is supported, as
the module is added to sys.modules first, then it is run. So you
can import it while its import is in progress.

As a quick work-around, you can add each module to the package:

# z1.py
if __name__ != '__main__':
    import sys, aaa
    aaa.z1 = sys.modules['aaa.z1']

from aaa import z2

# z2.py
if __name__ != '__main__':
    import sys, aaa
    aaa.z2 = sys.modules['aaa.z2']

from aaa import z1


HTH,
Martin

P.S. Notice that running a module as __main__ *and* importing it
circularly is also a problem (and is already in the non-package
case): the module gets loaded twice: once as __main__, and once
as z1.



More information about the Python-list mailing list