Python 没有名为 X 的模块 - 绝对导入

dab*_*ues 7 python python-import python-3.x

在我开始之前,我想说 - 我知道,有无数类似的问题,但我找不到我的问题的答案。我有一个这样的目录结构:

.
??? project
?   ??? A
?   ?   ??? __init__.py
?   ?   ??? somelib.py
?   ??? B
?   ??? C
?   ?   ??? C
?   ?       ??? foo.py
?   ?       ??? __init__.py
?   ??? __init__.py
??? run.sh
Run Code Online (Sandbox Code Playgroud)

运行.sh

python3 project/C/C/foo.py

foo.py :

from project.A.somelib import somefunc


VS Code 实际上获得了智能感知foo.py- 它告诉我可以从somelib. 但是当我运行时run.sh,我收到此错误消息:

from project.A.somelib import somefunc
ModuleNotFoundError: No module named 'project'
Run Code Online (Sandbox Code Playgroud)

有没有办法在保留这个目录结构的同时解决这个问题?


  • 添加project/__init__.py什么都没改变
  • sys.pathfoo.py如下所示:
['/home/dabljues/projects/project/project/C/C', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/usr/lib/python3.7/site-packages']
Run Code Online (Sandbox Code Playgroud)

限制:

  • 我既不能sys.path在文件中也不能PYTHONPATH在运行脚本之前修改
  • 我无法安装任何东西
  • 我没有 sudo 访问权限
  • 我无法创建 virtualenv,因为脚本应该是可下载且可快速执行的

Arn*_*rne 8

VSCode 或 Pycharm 等 IDE 对项目做出自己的假设,并且通常会正确链接模块,即使最终运行代码的解释器不能。

project.A.somelib无法找到的原因在您的sys.path输出中可见,它为您提供了 python 将搜索模块的位置。由于'/home/dabljues/projects/project/project'未包含,python 无法在运行时解析它。


快速破解

您可以手动将路径添加到sys.path,或者通过import sys; sys.insert(0, '/home/dabljues/projects/project/project/')foo.py任何其他导入发生之前在源文件中运行,或者通过export PYTHONPATH="${PYTHONPATH}:/home/dabljues/projects/project/project/"run.sh.


安装项目

由于看起来您正在开发一个库,您不妨使用 python 提供的机制来使库可共享,从而解决任何导入问题。setup.py向项目根目录添加一个最小值(即/home/dabljues/projects/project/project/setup.py):

from setuptools import setup, find_packages


setup(
    name='project',
    version='0.1.0',
    packages=find_packages('project'),
)
Run Code Online (Sandbox Code Playgroud)

并以可编辑模式安装您的项目:

$ python3 -m pip install -e .
Run Code Online (Sandbox Code Playgroud)

这将在您的python3可执行文件中放置一个指向site-packages项目根目录的链接,这样无论何时您使用python3.


测试

我包含print(__name__)在所有 python 文件的顶部以获得一些输出。

运行 run.sh 而不安装包:

$ sh run.sh 
Traceback (most recent call last):
  File "project/C/C/foo.py", line 1, in <module>
    from project.A.somelib import somefunc
ModuleNotFoundError: No module named 'project'
Run Code Online (Sandbox Code Playgroud)

安装后

$ sh run.sh 
__main__
project.A.somelib
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,project.C.C.foo是作为一个脚本执行,但发现所有以启动进口project,因为project安装。