Python从父包导入模块

5

我在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中?

你看过包内导入吗?或者重构你的包以避免这个问题。 - jonrsharpe
重构我的包应该怎么做? - mickzer
不要将共享数据放在顶层,将其移动到子模块中。 - jonrsharpe
2个回答

2
您可以使用相对导入来实现这一点。例如 -
在您的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中尝试导入app并使用那些仅在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中。请重新思考一下。

从..导入shared_data会出现ValueError错误:尝试相对于顶级包之外的导入。 - mickzer
1
你在运行什么?显然,你要么是在sub_app中运行Python,要么直接在其中运行文件,如果是这样,你不能使用相对导入。我以为sub_app只是app内的一个子包? - Anand S Kumar
你说得对,我是从 sub_app 内部运行它的,我的错。 - mickzer

2

您在这里有几个问题,其中一个是隐藏的。

看起来您正在尝试以以下方式调用程序:

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__.pyapp/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_appsub_app 依赖于 app。这两者都需要其他一个先被加载才能进行加载 - 当然这是不可能的。您应该重构代码以避免循环导入。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接