如何构建我的Python项目以允许从子目录导入命名模块

Bri*_*HVB 6 python organization python-3.x

这是我的目录结构:

Projects
    + Project_1
    + Project_2
    - Project_3
        - Lib1
            __init__.py # empty
            moduleA.py
        - Tests
            __init__.py # empty
            foo_tests.py
            bar_tests.py
            setpath.py
        __init__.py     # empty
        foo.py
        bar.py
Run Code Online (Sandbox Code Playgroud)

目标:

  1. 有一个有组织的项目结构
  2. 必要时能够独立运行每个.py文件
  3. 能够引用/导入兄弟和表兄弟模块
  4. 保留每个文件开头的所有import/from语句.

我通过使用上述结构实现了#1

通过执行以下操作,我大部分都达到了2,3和4(按照这本优秀指南的建议)

在任何需要访问父模块或堂兄模块的软件包(例如上面的Tests目录)中,我包含一个名为setpath.py的文件,其中包含以下代码:

import os
import sys
sys.path.insert(0, os.path.abspath('..'))

sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('...'))
Run Code Online (Sandbox Code Playgroud)

然后,在需要父/表兄弟访问的每个模块中,例如foo_tests.py,我可以编写一个很好的干净的导入列表,如下所示:

import setpath      # Annoyingly, PyCharm warns me that this is an unused import statement
import foo.py
Run Code Online (Sandbox Code Playgroud)

在setpath.py中,第二次和第三次插入对于此示例并非严格必要,但作为故障排除步骤包含在内.

我的问题是,这仅适用于直接引用模块名称的导入,而不适用于引用该包的导入.例如,在bar_tests.py中,当直接运行bar_tests.py时,下面的两个语句都不起作用.

import setpath

import Project_3.foo.py  # Error
from Project_3 import foo  # Error
Run Code Online (Sandbox Code Playgroud)

我收到错误"ImportError:没有名为'Project_3'的模块".

奇怪的是,我可以直接从PyCharm中运行文件,它运行正常.我知道PyCharm正在使用Python Path变量做一些幕后魔术,以使一切正常,但我无法弄清楚它是什么.由于PyCharm只是运行python.exe并设置了一些环境变量,因此应该可以从Python脚本本身克隆此行为.

由于与这个问题没有密切关系的原因,我必须bar使用Project_3限定符来引用.

我对任何能够实现上述目标的解决方案持开放态度,同时仍然符合我之前的目标.如果有一个更好的工作,我也会对备用目录结构开放.我已经阅读了关于导入和包的Python文档,但仍然处于亏损状态.我认为一种可能的途径可能是手动设置__path__变量,但我不确定需要更改哪一个或将其设置为什么.

Rob*_*rtT 2

这些类型的问题属于“主要基于意见”,所以让我分享我的意见,我将如何做。

\n\n

首先“必要时能够独立运行每个 .py 文件”:该文件要么是一个模块,所以不应该直接调用它,要么它是独立的可执行文件,那么它应该从顶层开始导入其依赖项(您可以避免它在代码中,或者更确切地说,通过使用 setup.py entry_points 将其移动到公共位置,但随后您以前的可执行文件会有效地转换为模块)。是的,这是 Python 模块模型的弱点之一,它会导致误解。

\n\n

其次,使用 virtualenv(或 Python3 中的 venv)并将每个 Project_x 放入单独的一个中。这样项目的名称就不会成为 Python 模块路径的一部分。

\n\n

第三,您提供的链接提到了 setup.py \xe2\x80\x93 您可以使用它。将自定义代码放入 Project_x/src/mylib1,创建 src/mylib1/setup.py,最后将模块放入 src/mylib1/mylib1/module.py。然后,您可以像任何其他包一样通过 pip 安装代码(或 pip -e,这样您就可以直接使用代码而无需重新安装它,但遗憾的是它有一些限制)。

\n\n

最后,正如您已经在评论中确认的那样;)。您当前模型的问题是sys.path.insert(0, os.path.abspath(\'...\'))您错误地使用了 Python 模块的表示法,该表示法对于系统路径不正确,应替换为\'../..\'按预期工作。

\n