Recursive import within packages

Stian Søiland stain at ozelot.stud.ntnu.no
Thu Sep 11 22:07:57 EDT 2003


all examples performed with:

Python 2.3+ (#2, Aug 10 2003, 11:09:33) 
[GCC 3.3.1 20030728 (Debian prerelease)] on linux2
(2, 3, 0, 'final', 1)



This is a recursive import:

-- blapp.py --
print "Blapp start"
import blupp
print "Blapp end"

-- blupp.py --
print "Blupp start" 
import blapp
print "Blupp end"


This works like a charm:

>>> import blapp
Blapp start
Blupp start
Blupp end
Blapp end


The same files with a directory thing with __init__:

>>> from thing import blapp
Blapp start
Blupp start
Blupp end
Blapp end



Changing the imports to import thing.blupp and import thing.blapp:

>>> from thing import blapp
Blapp start
Blupp start
Blupp end
Blapp end



Adding a print of the module with:

print "Blapp end", blupp


results in:

>>> import blapp
Blapp start
Blupp start
Blupp end <module 'blapp' from 'blapp.py'>
Blapp end <module 'blupp' from 'blupp.py'>




Changing to:

import thing.blapp as blapp  

and vice versa


>>> from thing import blapp
Blapp start
Blupp start
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "thing/blapp.py", line 2, in ?
    import thing.blupp as blupp
  File "thing/blupp.py", line 2, in ?
    import thing.blapp as blapp
AttributeError: 'module' object has no attribute 'blapp'



Changing to:

from thing import blapp

and vice versa


>>> from thing import blapp
Blapp start
Blupp start
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "thing/blapp.py", line 2, in ?
    from thing.blupp import blupp
  File "thing/blupp.py", line 2, in ?
    from thing import blapp
ImportError: cannot import name blapp




And finally:

print "Blapp start"
import thing.blupp
print "Blapp end", thing.blupp


(and vice versa)


>>> from thing import blapp
Blapp start
Blupp start
Blupp end
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "thing/blapp.py", line 2, in ?
    import thing.blupp
  File "thing/blupp.py", line 3, in ?
    print "Blupp end", thing.blapp
AttributeError: 'module' object has no attribute 'blapp'


Adding a print of dir(thing) verifies  this:

-- blapp.py -- (and vice versa)
print "Blapp start"
import thing.blupp
print dir(thing)
print "Blapp end"


>>> import thing.blupp
Blupp start
Blapp start
['__builtins__', '__doc__', '__file__', '__name__', '__path__']
Blapp end
['__builtins__', '__doc__', '__file__', '__name__', '__path__', 'blapp']
Blupp end



-- blapp.py -- 

print "Blapp start"
import thing.blupp
import thing.notexisting
print "Blapp end", thing.blupp

>>> from thing import blupp
Blupp start
Blapp start
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "thing/blupp.py", line 2, in ?
    import thing.blapp
  File "thing/blapp.py", line 3, in ?
    import thing.notexisting
ImportError: No module named notexisting



Now, could anyone please explain to me the logic involved here? 

Why is circular import only valid when accessing them without package
name? It clearly works by not using full references, even to print the
module while the other module is being loaded. 

The user-fix to the problem is of course:

  a) Don't use circular references
  b) delay circular import until module usage
     (ie. within class/function)
  c) Use relative modulenames (works only within the same package)
  d) import thing.blapp - but don't expect thing.blapp to be there
     until module usage (ie. within class/function)


But my question is why this works outside packages, but not inside
packages. This must be a bug, but I can't find it anywhere in the bugs
section on SourceForge.

(A google search for 'circular import' on Google seems impossible =) Way
too many circle-square-shape-examples!)

The FAQ says:
 
 Circular imports are fine where both modules use the "import <module>"
 form of import. They fail when the 2nd module wants to grab a name
 out of the first ("from module import name") and the import is at    
 the top level. That's because names in the 1st are not yet available,
 (the first module is busy importing the 2nd).  

However that is not correct in this case, the "thing" module is loaded
and works fine, it is the name thing.blapp that is not registered until
after blapp is loaded. In my opinion thing.blapp should be bound before
the actuall import of thing.blapp.

Actually, thing.blapp gets registered into sys.modules right away.


-- 
Stian Søiland               Being able to break security doesn't make
Trondheim, Norway           you a hacker more than being able to hotwire
http://stain.portveien.to/  cars makes you an automotive engineer. [ESR]




More information about the Python-list mailing list