Python 软件包在安装后找不到其模块之一
Python package cannot find one of its modules after installation
我正在尝试构建一个 Python 包。为了简单起见,我只会提到与问题相关的部分:
包(目录)名为 moranpycess
,其中包含三个相关文件:
- 整个包的初始化文件
__init__.py
:
from .Individual import Individual
from .MoranProcess import MoranProcess
一个名为 Individual
的模块,其中包含 class Individual
.
一个名为 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
发生了变化,我会怀疑是恶作剧并开始寻找替代方案。
我正在尝试构建一个 Python 包。为了简单起见,我只会提到与问题相关的部分:
包(目录)名为 moranpycess
,其中包含三个相关文件:
- 整个包的初始化文件
__init__.py
:
from .Individual import Individual
from .MoranProcess import MoranProcess
一个名为
Individual
的模块,其中包含 classIndividual
.一个名为
MoranProcess
的模块,其中包含一个 classMoranProcess
。在顶部,它导入前一个模块: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
发生了变化,我会怀疑是恶作剧并开始寻找替代方案。