Python 软件包在安装后找不到其模块之一

Python package cannot find one of its modules after installation

我正在尝试构建一个 Python 包。为了简单起见,我只会提到与问题相关的部分: 包(目录)名为 moranpycess,其中包含三个相关文件:

  1. 整个包的初始化文件__init__.py:
from .Individual import Individual
from .MoranProcess import MoranProcess
  1. 一个名为 Individual 的模块,其中包含 class Individual.

  2. 一个名为 MoranProcess 的模块,其中包含一个 class MoranProcess。在顶部,它导入前一个模块:import Individual.

我用 python -m pip install .
安装包 然后我运行测试一下包能不能正常导入:python -c 'import moranpycess'.

我得到:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/runner/work/angry-moran-simulator/angry-moran-simulator/moranpycess/__init__.py", line 18, in <module>
    from .MoranProcess import MoranProcess
  File "/home/runner/work/angry-moran-simulator/angry-moran-simulator/moranpycess/MoranProcess.py", line 22, in <module>
    import Individual
ModuleNotFoundError: No module named 'Individual'
Error: Process completed with exit code 1.

这对我来说很奇怪,因为似乎 Python 解释器可以找到包,包导入相应的 classes 但解释器还尝试执行顶级模块导入并且(我不知道为什么)它找不到模块...
我是不是做错了什么?

编辑:

目录结构:

└── moranpycess
    ├── Individual.py
    ├── MoranProcess.py
    └── __init__.py

更新

我正在考虑这里提出的解决方案:

但是我不知道这是否是组织包裹的“正确”方式...

相对导入比绝对导入更难做到正确。它们也更脆弱(例如,如果您在导入时移动文件,它会损坏),所以除非您有充分的理由使用相对导入,否则我建议只使用绝对导入。

之后,您的 public API 在最顶层 __init__.py 中的定义将如下所示:

from moranpycess.MoranProcess import MoranProcess

__all__ = ["MoranProcess"]  # import hint that some tools use

虽然非public对象仍然可以通过以下方式在内部导入(例如在MoranProcess.py中):

from moranpycess.Individual import Individual 

绝对导入的好处在于,无论您在包中(或包外)的哪个位置,它们看起来总是一样的。


如果这样做,安装了您的软件包的用户应该能够像这样使用您的对象:

from moranpycess import MoranProcess  # directly gets the object, not module

您应该尽量避免弄乱 sys.path 以使您的导入正常工作,主要是因为这不是必需的。如果您所做的只是编写旨在以常规方式使用的常规 python 代码,那么内置导入机制应该可以很好地满足您的用例。

如果我要导入一个包并注意到 sys.path 发生了变化,我会怀疑是恶作剧并开始寻找替代方案。