我的目录结构:
test/
algo/
base.py
func.py
main.py
func.py
导入 base
和 main.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
答案 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
)时执行的命名空间。