.
(平级目录)或..
(父级目录)起头的import
语句。例如,from . import
表示从报错模块平级目录的包或模块中调用嵌套的包或模块或函数。__init__.py
指示当前文件夹为一个包。python path/to/main.py
中 python
命令的执行位置)无法查找到当前执行脚本引用的包含相对导入的模块的最小包结构。问题:相对导入是存在于包结构中,并在模块中使用的概念,而由 Python 解释器执行的程序是脚本文件,不应该存在相对导入。
解决方案:请使用绝对导入导入同级模块或包。若本地包文件存在于其它目录层级,考虑重新安排目录结构,或使用 PYTHONPATH
环境变量将本地包路径手动添加到 Python 解释器可识别包路径。详见文末扩展内容。
你真的需要相对导入吗?如果你明确地知晓答案,也许就不应该出现这个问题。
相对导入应当使用在包(由多个或多目录层级 *.py
模块组成)内模块中的 import
语句,用于内部模块功能之间的相互调用,而包内模块及功能则应当通过包外脚本调用。
因此你应该这样思考和解决:当前的代码结构真的存在包-模块层级关系吗?如果存在,你应当在包外部通过脚本引用任意包-模块功能;如果不存在,你应当使用绝对导入直接导入同级目录模块。
当你意识到自己当前所处的位置确实为包外部,但尝试通过包平级目录以外的目录导入该包时,也可能遭遇导入问题。
Python的默认包搜索路径为sys.path
,一般指向当前Python环境pip默认安装包的目录。
你可以通过export PYTHONPATH=$PWD
快速添加当前目录(包所在目录)到搜索路径。如为开发中包项目,建议使用 direnv 进行环境管理,如为长期依赖某些本地未发布的代码(包、模块)脚本文件,建议通过代码添加本地代码所在目录到sys.path
。
Stack Overflow: Relative imports for the billionth time
python3-cookbook: 10.9 将文件夹加入到sys.path
通过执行该文件能够完成某项任务,其中存在必要的任务执行逻辑(一般通过 if __name__ == '__main__:'
代码块明确任务的整体执行逻辑),notebook 也可以列入这一范畴;
Python 对象的集合,其内容为功能实现,目的是方便其它模块和脚本调用,因此不存在自身的运行逻辑(也即需要通过在其它文件中使用 import
语句调用,而非直接通过 python module.py
运行);
如果一个目录中存在多个模块,可以通过创建 __init__.py
文件将该当前目录标识为一个包。若多个模块放置于具有多层嵌套的目录当中,其逻辑关系为包(根目录)-> 子包(子目录)-> 模块(*.py);
从包/模块外部,按照目标模块的存在路径从外到内进行导入。绝对导入可以检索到三种来源的包:
PYTHONPATH
的模块和包。绝对导入示例:
import module
;from package import module
;from package.subpackage import module
)。位于同一包中的不同子包和模块,可以通过前缀.
标识存在调用关系的包/模块之间的路径依赖关系并进行相对调用。示例:
from . import module
;from .package import module
;from .packge.subpackge import module
;from . -> from ..
,以此类推。