Python 从父包导入
Python import from parent package
我在 Python 中遇到一些导入问题。
这是一个简单的错误示例。
我有这样的目录结构:
app
|---__init__.py
|---sub_app
|---__init__.py
代码:
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
但是我收到错误:
ImportError: No module named app
如何将 shared_data 字典导入 app/sub_app/__init__.py?
您可以为此使用 relative imports。例子-
在你的 app/sub_app/__init__.py
-
more_shared_data = {
'data': '12345'
}
from .. import shared_data
print shared_data
这应该适用于您提供的简单示例,但它确实会导致循环导入,app
正在导入 sub_app
并且 sub_app
正在导入 app
。
对于更复杂的用例,您可能会在定义特定元素之前遇到错误(如果您导入 sub_app),然后在 sub_app/__init__.py
中您尝试导入应用程序并使用那些元素仅在 sub_app
的导入语句之后定义。一个非常简单的例子,它会导致问题 -
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)
现在,如果您尝试导入 app
,您将收到错误 -
>>> 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'
你应该重新考虑 shared_data
是否属于 app/__init__.py
,或者它可以移动到 sub_app/__init__.py
然后从那里导入 app
。
你这里有几个问题,其中一个是隐藏的。
看起来您正在尝试调用您的程序:
python app/__init__.py
python app/sub_app/__init__.py
这会导致问题,因为主文件的目录被认为是程序的根目录。也就是为什么sub_app
看不到app
.
您可以像这样调用您的程序
python -m app.sub_app
这样python假设当前目录是根目录,在这个目录下寻找模块app.sub_app
。这会导致另一个问题。为了能够 运行 包,您需要在包中提供 __main__.py
(以及 __init__.py
)。如果模块不相互导入,那么调用顺序将是app/__init__.py
、app/sub_app/__init__.py
,然后是app/sub_app/__main__.py
app
|---__init__.py
|---sub_app
|---__init__.py
|---__main__.py
app/sub_app/__main__.py
可以做如下事情:
from app import shared_data
from . import more_shared_data
# or
from app.sub_app import more_shared_data
最后,隐藏的问题是你有循环导入。也就是说,app
依赖于 sub_app
而 sub_app
依赖于 app
。 app
和 sub_app
都需要先加载另一个,然后才能加载——这当然是不可能的。您应该重构代码以避免循环导入。
我在 Python 中遇到一些导入问题。
这是一个简单的错误示例。
我有这样的目录结构:
app
|---__init__.py
|---sub_app
|---__init__.py
代码:
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
但是我收到错误:
ImportError: No module named app
如何将 shared_data 字典导入 app/sub_app/__init__.py?
您可以为此使用 relative imports。例子-
在你的 app/sub_app/__init__.py
-
more_shared_data = {
'data': '12345'
}
from .. import shared_data
print shared_data
这应该适用于您提供的简单示例,但它确实会导致循环导入,app
正在导入 sub_app
并且 sub_app
正在导入 app
。
对于更复杂的用例,您可能会在定义特定元素之前遇到错误(如果您导入 sub_app),然后在 sub_app/__init__.py
中您尝试导入应用程序并使用那些元素仅在 sub_app
的导入语句之后定义。一个非常简单的例子,它会导致问题 -
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)
现在,如果您尝试导入 app
,您将收到错误 -
>>> 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'
你应该重新考虑 shared_data
是否属于 app/__init__.py
,或者它可以移动到 sub_app/__init__.py
然后从那里导入 app
。
你这里有几个问题,其中一个是隐藏的。
看起来您正在尝试调用您的程序:
python app/__init__.py
python app/sub_app/__init__.py
这会导致问题,因为主文件的目录被认为是程序的根目录。也就是为什么sub_app
看不到app
.
您可以像这样调用您的程序
python -m app.sub_app
这样python假设当前目录是根目录,在这个目录下寻找模块app.sub_app
。这会导致另一个问题。为了能够 运行 包,您需要在包中提供 __main__.py
(以及 __init__.py
)。如果模块不相互导入,那么调用顺序将是app/__init__.py
、app/sub_app/__init__.py
,然后是app/sub_app/__main__.py
app
|---__init__.py
|---sub_app
|---__init__.py
|---__main__.py
app/sub_app/__main__.py
可以做如下事情:
from app import shared_data
from . import more_shared_data
# or
from app.sub_app import more_shared_data
最后,隐藏的问题是你有循环导入。也就是说,app
依赖于 sub_app
而 sub_app
依赖于 app
。 app
和 sub_app
都需要先加载另一个,然后才能加载——这当然是不可能的。您应该重构代码以避免循环导入。