无法从另一个目录进行 Python 导入



我无法从另一个目录中的Python文件导入。目录结构:

some_root/
- __init__.py
- dir_0/
- __init__.py
- dir_1/
- __init__.py
- file_1.py
- dir_2/
- __init__.py
- file_2.py

file_1.py有一些导出成员:

# file_1.py
def foo():
pass

file_2.py尝试从file_1.py:导入成员

# file_2.py
from dir_0.dir_1.file_1 import foo

但无论是绝对的还是相对的重要性似乎都不起作用。如何正确导入Python?如果我能避免使用sys.path.insert,那就太好了,但如果没有办法,我想事情就是这样。

不要打乱搜索路径

你没有摆弄sys.path是对的。这是不推荐的,而且总是一个丑陋的变通方法。对此有更好的解决方案。

重新构造文件夹布局

请参阅关于打包的Python官方文档。

区分项目文件夹

包文件夹在你的情况下,它应该是这样的。

some_project
└── src
└── some_root
├── dir_0
│   ├── dir_1
│   │   ├── file_1.py
│   │   └── __init__.py
│   ├── dir_2
│   │   ├── file_2.py
│   │   └── __init__.py
│   └── __init__.py
└── __init__.py

使您的软件包可安装

使用该内容创建一个some_project/setup.cfg。在第5行和第6行保留换行符和缩进。他们必须是这样,但我不知道为什么。

[metadata]
name = some_project
[options]
package_dir=
=src
packages = find:
zip_safe = False
python_requires = >= 3
[options.packages.find]
where = src
exclude =
tests*
.gitignore

创建包含以下内容的some_project/setup.py

from setuptools import setup
setup()

"安装";包裹

这不是一个常见的安装。请参阅"开发模式"来了解这到底意味着什么。包未复制到/usr/lib/python/site-packages;只创建链接。

导航到项目文件夹some_project并运行

python3 -m pip install --editable .

不要忘记最后的.。根据您的操作系统和环境,可能需要将python3替换为py -3python或其他内容。

导入

您的file_2.py

import some_root
import some_root.dir_0
import some_root.dir_0.dir_1
from some_root.dir_0.dir_1 import file_1
file_1.foo()

但正如其他人在评论中所说。改进文件和文件夹的结构并降低其复杂性。

默认情况下,Python搜索路径包括在安装Python时有效固定的目录:如/usr/lib/python/site-packages

运行脚本时,包含正在执行的脚本的目录会添加到路径中。最重要的是,为了安全起见,当前工作目录是,而不是添加到路径中。(您不希望您的脚本以不同的方式工作,可能会根据其调用环境导入您意想不到的模块。这与强烈建议将.排除在PATH变量之外的原因相同。(

执行file_2.py时,some_root/dir_0/dir_2会添加到路径中,但如果some_root是当前工作目录,则some_root本身不在搜索路径上。这就是import dir_0.dir_1.file_1失败的原因。相对导入也会失败,因为some_root不是用于解析相对导入的根(或任何(包。

通常,如果你想在不安装代码的情况下运行代码,你可以将脚本保存在some_root中:

some_root/
file_a.py

- __init__.py
- dir_0/
- __init__.py
- dir_1/
- __init__.py
- file_1.py
- dir_2/
- __init__.py
file_2.py

file_a.py可以像一样简单

from dir_0.dir_2.file_2 import main

if __name__ == '__main__':
main()

CCD_ 30提供了一个入口点。(它仍然可以自己执行;它只是使用main,就像导入file_2.py的任何其他脚本一样,而不仅仅是直接跳到它的代码中。(