在我们开发 Python 项目时,经常会遇到项目目录下,子目录间模块导入的问题,例如:
我拥有如下目录 python-test:
├─bin
│ start.py
│ __init__.py
│
└─utils
│ base.py
│ __init__.py
其中 start.py 是我需要执行的文件,base.py 中定义了某函数方法(例如:hello_world()),并在 start.py 中被调用。
但是这时问题就来了,如果我在此时进入 bin 目录执行 start.py
则会报错:
Traceback (most recent call last):
File "start.py", line 4, in <module>
from utils.base import hello_world
ModuleNotFoundError: No module named 'utils'
显示无法找到包 utils
在 Python 中,包可以简单理解为文件系统中的目录,模块就是目录中的文件(包是特殊的模块),一个包含 __init__.py
文件的目录,就会认为是一个 Python 的常规包,但是这块很显然,我们创建了 __init__.py
文件,但是仍然显示无法找到 utils.
有很多方法可以解决上述问题。
方案一:相对导入
对项目做如下修改:
- 在 python-test 项目目录下,添加
__init__.py
文件 - 修改 start.py 的导入语句为
from ..utils.base import hello_world
- 在 python-test 上级目录执行
python -m python-test.bin.start
注:
python -m
-m mod : run library module as a script (terminates option list)
注意,这其实是将 python-test 作为一个包,将 start.py 作为其中的一个子模块导入的方式。
方案二:添加高一层的目录到 python modules path 下
import sys
sys.path.append("..")
sys.path 是一个字符串列表,用于指定模块的搜索路径,索引的0位,是执行文件所在路径(调用python解释器的脚本的目录),所以我们总是可以调用同目录下的文件,但是对于更高层的,我们就调用不了。
这是一种有效的方法,但是注意,如果使用这种方法,在你执行该文件时,你的执行路径是 ../bin/ 下,而不是 ../python-test/ 下。
而且,实时上直接进入执行目录,然后执行子模块脚本,这并不是一种好的模式,在生产环境中,我们应当尽量避免这种写法。