问题描述
我的文件夹结构如下
./fff
├── __init__.py
├── fg
│ ├── __init__.py
│ └── settings
│ ├── __init__.py
│ └── settings.py
└── obng
└── test.py
我想把fg/settings里面的settings.py作为一个模块导入test.py
我已经添加了行
从 ..fg.settings 导入设置
但是当我运行它时,它给了我以下错误
回溯(最近一次调用最后一次): 文件“/mnt/d/Repos/fff/obng/test.py”,第 1 行,在 从 ..fg.settings 导入设置 导入错误:尝试在没有已知父包的情况下进行相对导入
根据 https://docs.python.org/3/reference/import.html#package-relative-imports
支持这种类型的相对导入我在这里做错了什么?
解决方法
通常,当您将 python 模块作为主模块(如 python filename.py
)运行时,您不能使用相对导入,但可以使用 __package__
来实现这一点。记住 __package__
是 python 解析相对导入的方式:
1- 在您的根目录中创建一个名为 __init__.py
的文件 - fff
。 (我可以看到你拥有它,我提到了完整性)
2- 将此代码放在您的 test.py
模块之上:
if __name__ == '__main__' and not __package__:
import sys
sys.path.insert(0,<path to parent directory of root directory - fff>)
__package__ = 'fff.obng'
注意:sys.path
是 python 搜索模块以导入它们的地方。
3- 现在将您的相对导入语句放在上面的代码之后(在 if 语句中,因为我们不想在导入 test.py
时弄乱):
from ..fg.settings import settings
现在你可以叫你test.py
,它会毫无问题地运行。我不建议使用这些技巧,但展示语言的灵活性并在某些情况下做你想做的事情是有益的。
其他好的解决方案:我认为绝对导入比这更简单、更干净。另外看看@Mr_and_Mrs_D 的回答,另一个好的解决方案是使用 -m
命令行标志运行您的模块。
这是你如何运行你的项目的问题——你应该从顶级包的父目录运行
$ cd ../fff
$ python -m fff.obng.test # note no py
然后将正确解析相对导入。这是一个直接从其文件夹运行脚本的反模式
,相对导入基于当前模块的名称。运行时
python fff/obng/test.py
test.py 的名称将为 __main__
,导入将不起作用。
在导入 fff.obng.test 的 fff 模块之外有另一个名为“test.py”的脚本会起作用
fff_top
├── fff
│ ├── fg
│ │ ├── __init__.py
│ │ └── settings
│ │ ├── __init__.py
│ │ └── settings.py
│ ├── __init__.py
│ └── obng
│ ├── __init__.py
│ └── test.py
└── test.py
使用 fff_top/test.py:
import fff.obng.test
然后,运行“外部”test.py 应该没问题:
python fft_top/test.py
或者,我建议完全放弃相对进口。一种方法是为您编写的每个包使用虚拟环境,例如使用 venv 库:
python -m venv venv
然后,在根文件夹中添加一个 setup.py 内容:
from setuptools import setup,find_packages
setup(name="fff",packages=find_packages())
并更改 obng/test.py
中的导入:
from fff.fg.settings import settings
最后,激活您的虚拟环境:
source venv/bin/activate
并以可编辑模式安装您的软件包:
pip install -e .
然后,在您完成上述所有步骤后:
python fff/obng/test.py
应该可以。