导入再次导入另一个模块的模块时出现 ModuleNotFoundError

时间:2021-03-03 13:05:03

标签: python python-3.x python-import importerror

我的目录结构:

test/
    algo/
        base.py
        func.py
    main.py

func.py 导入 basemain.py 导入 func。脚本是:

# base.py

def base():
    pass
# func.py

from base import base
def func():
    base()

if __name__ == '__main__':
   func()
# main.py 

from algo.func import func 
if __name__ == '__main__':
   func()

当我执行 func.py 时,一切正常:

cd test/algo
python func.py # OK

但是当运行 main.py 失败时:

cd test
python main.py # => ModuleNotFoundError: No module named "base"

现在,如果我在 . 中为 base 添加 func.py 前缀:

from .base import base # add dot prefix here
def func():
    base()

if __name__ == '__main__':
   func()

这一次,运行 main.py 没问题,但是运行 func.py 导致错误: ModuleNotFoundError: No module named '__main__.base'; '__main__' is not a package

为什么会这样?

base中导入func的正确方法是什么,使得func可以直接执行,并被main导入?

谢谢!

我的环境:MacOS,python3.7.4

1 个答案:

答案 0 :(得分:0)

看起来您将 algo/ 视为 Python 包,在这种情况下您可以使用:

# func.py
from algo.base import base

为什么有效?这是因为 Python 解释器在其模块搜索路径 (sys.path) 中添加了执行的文件目录。所以 Python 在它下面看到了一个 algo/ 目录,让 import algo 和朋友们工作。

现在,如果您想直接运行 func.py,您会遇到一个问题:algo/ 目录不再能从 sys.path 中发现,并且您遇到了导入错误,而您的代码是对的。

完成这项工作的正确方法是告诉 Python 如何找到您的包。

快速而肮脏的方法是使用 PYTHONPATH 将包含您的包的目录添加到 sys.path

PYTHONPATH=. python3 algo/func.py

干净的方法将在稍后出现:如果您正确打包您的项目(通过向其中添加一个 pyproject.toml 和一个 setup.cfg,例如参见 https://packaging.python.org/tutorials/packaging-projects/),那么您将能够安装您的软件包:

pip install .

“安装”的意思是“将包放在 Python 期望的地方”,所以很明显,一旦安装,所有 import algo 都可以工作,无需修改 PYTHONPATH,并且不依赖于您当前的工作目录。

最后一句话,你应该在你的 __init__.py 文件夹中放置一个空的 algo/ 文件,使其成为一个合适的 Python 包,没有它就是一个 Python namespace package,有点不同,而不是什么你真的想要。

而且,您听说过 __main__.py 吗?它是您运行 python3 -m YOUR_PACKAGE(在您的示例中为 python3 -m algo)时执行的命名空间。