如何从模块的项目结构外部导入 python 模块而不出现 ModuleNotFoundError?
How can I import python modules from outside the module's project structure without getting a ModuleNotFoundError?
我创建了一个 python 项目,使用 Pycharm 如果重要的话,它看起来像这样:
outer_dir/
outside_main.py
module_example/
module_main.py
tests/
test_1.py
…
level_1/
foo_1.py
level_2/
foo_2.py
main.py
从 foo_1.py
调用函数
foo_1.py
从 foo_2.py
调用函数
我试图模拟的一般用例是一个名为 module_example
的 python“包”或 repo,已被 outside_main.py
下载并使用,级别与顶级包目录。
这是 module_main.py 的样子:
# module_main.py
from level_1.foo_1 import foo_function_1
from level_1.level_2.foo_2 import foo_function_2
def main():
print(foo_1())
print(foo_2())
if __name__ == "__main__":
main()
我可以从 test_1.py
调用这个顶级脚本,就像这样:
# test_1.py
from module_main import main
if __name__ == "__main__":
main()
但是,当我尝试从 module_example
目录外部使用 main() 时,代码如下:
# outside_main.py
from module_example.module_main import main
if __name__ == "__main__":
main()
我收到这个错误:
Traceback (most recent call last):
File "/path/to/outside_main.py", line 1, in <module>
from module_example.module_main import main
File "/path/to/module_example/module_main.py", line 1, in <module>
from level_1.foo_1 import foo_function_1
ModuleNotFoundError: No module named 'level_1'
似乎正在发生的事情是,无论导入的 python 脚本的目录如何,都会相对于执行主脚本的目录搜索它自己的导入。
我正在寻找一种导入方法,无论我是调用 outside_main.py
还是 test_1.py
,也无论终端当前指向哪个目录,该方法都同样有效。
我读过 this post 关于 python 导入如何工作的内容,它基本上表明我运气不好,但这对我来说毫无意义,我正在努力做正在使用来自 github 的某人的开源库进行模拟,他们通常在他们的回购协议中有一个 tests
文件夹,工作正常,但我也可以在我的项目中解压缩整个回购协议并在他们的 py 上调用导入文件没有问题。他们是怎么做到的?
解决方案 1:
使用 explicit relative imports (relative to the files inside the directory module_example
). Note that the usage of implicit relative imports 已在 Python3
中删除
Implicit relative imports should never be used and have been removed in Python 3.
outer_dir/module_example/module_main.py
# Note the "." in the beginning signifying it is located in the current folder (use ".." to go to parent folder)
from .level_1.foo_1 import foo_function_1
from .level_1.level_2.foo_2 import foo_function_2
# All the rest the same
解决方案 2:
在您的 PYTHONPATH
环境变量中包含 module_example
的路径(或者您也可以 choose 直接更新 sys.path
)
export PYTHONPATH=$(pwd):$(pwd)/module_example
输出:
以上两种解决方案对我来说都是成功的。
修复前:
$ python3 outside_main.py
Traceback (most recent call last):
File "outside_main.py", line 1, in <module>
from module_example.module_main import main
File "/home/nponcian/Documents/PearlPay/Program/2021_07Jul_31_Whosebug/1/module_example/module_main.py", line 1, in <module>
from level_1.foo_1 import foo_function_1
ModuleNotFoundError: No module named 'level_1'
修复后:
$ python3 outside_main.py
This is foo_function_1
This is foo_function_2
在进入 sys.path
补丁的地狱之前,我建议将您当前位于 module_example
中的代码包装到 package_example
目录中,添加一个 setup.py
并在
中抛出一些 __init__.py
制作 package_example
一个 git 仓库。
在您要使用 module_example.[...]
的每个其他项目中,您创建一个 venv
和 pip -e /path/to/package_example
。
outer_dir/
outside_main.py
package_example/
.git/
...
setup.py
module_example/
__init__.py
module_main.py
tests/
...
其中__init__.py
(每个包含要导入的模块的子目录中的一个)只能是空文件并且setup.py
必须根据distutils documentation填充。
我创建了一个 python 项目,使用 Pycharm 如果重要的话,它看起来像这样:
outer_dir/
outside_main.py
module_example/
module_main.py
tests/
test_1.py
…
level_1/
foo_1.py
level_2/
foo_2.py
main.py
从 foo_1.py
调用函数
foo_1.py
从 foo_2.py
我试图模拟的一般用例是一个名为 module_example
的 python“包”或 repo,已被 outside_main.py
下载并使用,级别与顶级包目录。
这是 module_main.py 的样子:
# module_main.py
from level_1.foo_1 import foo_function_1
from level_1.level_2.foo_2 import foo_function_2
def main():
print(foo_1())
print(foo_2())
if __name__ == "__main__":
main()
我可以从 test_1.py
调用这个顶级脚本,就像这样:
# test_1.py
from module_main import main
if __name__ == "__main__":
main()
但是,当我尝试从 module_example
目录外部使用 main() 时,代码如下:
# outside_main.py
from module_example.module_main import main
if __name__ == "__main__":
main()
我收到这个错误:
Traceback (most recent call last):
File "/path/to/outside_main.py", line 1, in <module>
from module_example.module_main import main
File "/path/to/module_example/module_main.py", line 1, in <module>
from level_1.foo_1 import foo_function_1
ModuleNotFoundError: No module named 'level_1'
似乎正在发生的事情是,无论导入的 python 脚本的目录如何,都会相对于执行主脚本的目录搜索它自己的导入。
我正在寻找一种导入方法,无论我是调用 outside_main.py
还是 test_1.py
,也无论终端当前指向哪个目录,该方法都同样有效。
我读过 this post 关于 python 导入如何工作的内容,它基本上表明我运气不好,但这对我来说毫无意义,我正在努力做正在使用来自 github 的某人的开源库进行模拟,他们通常在他们的回购协议中有一个 tests
文件夹,工作正常,但我也可以在我的项目中解压缩整个回购协议并在他们的 py 上调用导入文件没有问题。他们是怎么做到的?
解决方案 1:
使用 explicit relative imports (relative to the files inside the directory module_example
). Note that the usage of implicit relative imports 已在 Python3
Implicit relative imports should never be used and have been removed in Python 3.
outer_dir/module_example/module_main.py
# Note the "." in the beginning signifying it is located in the current folder (use ".." to go to parent folder)
from .level_1.foo_1 import foo_function_1
from .level_1.level_2.foo_2 import foo_function_2
# All the rest the same
解决方案 2:
在您的 PYTHONPATH
环境变量中包含 module_example
的路径(或者您也可以 choose 直接更新 sys.path
)
export PYTHONPATH=$(pwd):$(pwd)/module_example
输出:
以上两种解决方案对我来说都是成功的。
修复前:
$ python3 outside_main.py
Traceback (most recent call last):
File "outside_main.py", line 1, in <module>
from module_example.module_main import main
File "/home/nponcian/Documents/PearlPay/Program/2021_07Jul_31_Whosebug/1/module_example/module_main.py", line 1, in <module>
from level_1.foo_1 import foo_function_1
ModuleNotFoundError: No module named 'level_1'
修复后:
$ python3 outside_main.py
This is foo_function_1
This is foo_function_2
在进入 sys.path
补丁的地狱之前,我建议将您当前位于 module_example
中的代码包装到 package_example
目录中,添加一个 setup.py
并在
__init__.py
制作 package_example
一个 git 仓库。
在您要使用 module_example.[...]
的每个其他项目中,您创建一个 venv
和 pip -e /path/to/package_example
。
outer_dir/
outside_main.py
package_example/
.git/
...
setup.py
module_example/
__init__.py
module_main.py
tests/
...
其中__init__.py
(每个包含要导入的模块的子目录中的一个)只能是空文件并且setup.py
必须根据distutils documentation填充。