I\'m getting a \'module object has no attribute ...\" error when trying to use a package heirarchy I created. The error is reminiscant of the error you get when there is a circ
(This is, I believe, mostly supported by the explanation at http://docs.python.org/faq/programming.html#how-can-i-have-modules-that-mutually-import-each-other)
When the Python interpreter encounters a line of the form import a.b.c
, it runs through the following steps. In pseudo-python:
for module in ['a', 'a.b', 'a.b.c']:
if module not in sys.modules:
sys.modules[module] = (A new empty module object)
run every line of code in module # this may recursively call import
add the module to its parent's namespace
return module 'a'
There are three important points here:
The modules a, a.b, and a.b.c get imported in order, if they haven't been imported already
A module does not exist in its parent's namespace until it has completely finished being imported. So module a
does not have a b
attribute until a.b
has been imported completely.
No matter how deep your module chain is, even if you import a.b.c.d.e.f.g
, your code only gets one symbol added to its namespace: a
.
So when you later try to run a.b.c.d.e.f.g.some_function()
, the interpreter has to traverse all the way down the chain of modules to get to that method.
Based on the code that you have posted, the problem seems to lie in the print statement in alpha/bravo/echo/__init__.py
. What the interpreter has done by the time it gets there is roughly this:
Set up an empty module object for alpha in sys.modules
Run the code in alpha/__init__.py (Note that dir(alpha) won't contain 'bravo' at this point)
Set up an empty module object for alpha.bravo in sys.modules
Run the code in alpha/bravo/__init__.py:
4.1 Set up an empty module object for alpha.bravo.charlie in sys.modules
4.2 Run the code in alpha/bravo/charlie/__init__.py:
4.2.1 Set up an empty module object for alpha/bravo/echo in sys.modules
4.2.2 Run the code in alpha/bravo/echo/__init__.py:
4.2.2.1 Set up an empty module object for alpha/bravo/delta in sys.modules
4.2.2.2 Run the code in alpha/bravo/delta/__init__.py -- This finishes, so 'delta' is added to 'alpha.bravo's symbols.
4.2.2.3 Add 'alpha' to echo's symbols. This is the last step in import alpha.bravo.delta
.
At this point, if we call dir() on all of the modules in sys.modules, we will see this:
'alpha': ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__return__']
(this is essentially empty)
'alpha.bravo': ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'delta']
(delta has finished being imported, so it's here)
'alpha.bravo.charlie': ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
(empty)
'alpha.bravo.delta': ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__return__', 'delta.foo']
(This is the only one that has completed)
'alpha.bravo.echo': ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__return__', 'alpha']
Now the intepreter continues with alpha/bravo/echo/__init__.py, where it encounters the line print alpha.bravo.delta.delta_foo(1)
. That starts this sequence:
alpha
-- this returns the still-empty alpha
module.alpha.bravo
isn't finished being initialized yet, so bravo hasn't been inserted into alpha's symbol table.This is the same thing that happens during a circular import -- the module isn't finished being initialized, so the symbol table isn't completely updated, and attribute access fails.
If you were to replace the offending line in echo/__init__.py with this:
import sys
sys.modules['alpha.bravo.delta'].delta_foo(1)
That would probably work, since delta is completely initialized. But until bravo is complete (after echo and charlie return), the symbol table for alpha won't be updated, and you won't be able to access bravo through it.
Also, as @Ric Poggi says, if you change the import line to
from alpha.bravo.delta import delta_foo
Then that will work. In this case, because from alpha.bravo.delta
goes right to the sys.modules dict, rather than traversing from alpha to bravo to delta, it can get the function from the delta module and assign it to a local variable, which you can then access without any trouble.
Instead of using absolute imports, it might help to use relatives.
i.e.
alpha/bravo/_init_.py
import alpha.bravo.charlie
should be
import charlie
Otherwise, it probably is a circular import. i.e. if you import alpha.bravo.charlie from charlie, that means
alpha/__init__.py
bravo/__init__.py
charlie/__init__.py
All are loaded (or rather, prevented from doing so since they're already loaded). That might cause the problem you're seeing.