Reputation: 6358
I'm having some trouble with imports in Python.
Here is a simple example of what's going wrong.
I have a directory structure like this:
app
|---__init__.py
|---sub_app
|---__init__.py
The code:
app/__init__.py
shared_data = {
'data': 123
}
from sub_app import more_shared_data
print more_shared_data
app/sub_app/__init__.py
more_shared_data = {
'data': '12345'
}
from app import shared_data
print shared_data
However I get the error:
ImportError: No module named app
How do I import the shared_data dict, into app/sub_app/__init__.py?
Upvotes: 5
Views: 4864
Reputation: 40853
You have a few problems here, one of which is hidden.
It looks like you are trying to invoke your program like:
python app/__init__.py
python app/sub_app/__init__.py
This causes problems in that the directory of the main file is considered to be the root directory of the program. That is, why sub_app
cannot see app
.
You can instead invoke your programs like such
python -m app.sub_app
This way python assumed the current directory is the root directory and looks for the module app.sub_app
under this directory. This causes another problem though. To be able to run a package you need to provide a __main__.py
in the package (as well as __init__.py
). If the modules do not import each other, then order of invocation will be app/__init__.py
, app/sub_app/__init__.py
, and then app/sub_app/__main__.py
app
|---__init__.py
|---sub_app
|---__init__.py
|---__main__.py
app/sub_app/__main__.py
can do stuff like:
from app import shared_data
from . import more_shared_data
# or
from app.sub_app import more_shared_data
Finally, the hidden problem is that you have circular imports. That is, app
depends on sub_app
and sub_app
depends on app
. That both app
and sub_app
need the other to be loaded, before they can load -- this is of course impossible. You should refactor your code to avoid circular imports.
Upvotes: 2
Reputation: 91009
You can use relative imports for this . Example -
In your app/sub_app/__init__.py
-
more_shared_data = {
'data': '12345'
}
from .. import shared_data
print shared_data
This should work for the simple example you have provided , but it does lead to circular import , app
is importing sub_app
and sub_app
is importing app
.
For more complex usecases, you can end up with errors (If you import sub_app) before defining specific elements, and then in sub_app/__init__.py
you try to import app and use those elements that are only defined after the import statement for sub_app
. A very simple example where it would cause issue -
app/__init__.py
-
from .sub_app import more_shared_data
print(more_shared_data)
shared_data = {
'data': 123
}
app/sub_app/__init__.py
-
more_shared_data = {
'data': '12345'
}
from .. import shared_data
print(shared_data)
Now, if you try to import app
, you will get the error -
>>> import app
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<some file>\__init__.py", line 1, in <module>
from .shared import more_shared_data
File "<some file>\sub_app\__init__.py", line 4, in <module>
from .. import shared_data
ImportError: cannot import name 'shared_data'
You should re-think if shared_data
does belong to app/__init__.py
, or it can be moved to sub_app/__init__.py
and then imported from there in app
.
Upvotes: 2