Python 3.10绝对导入用法及跨目录跨项目导入问题咨询
核心规则前置
Python 3.x 默认启用绝对导入,所有绝对导入的路径起点是当前Python运行时sys.path列表中包含的顶级目录,只有被纳入sys.path的目录下的包、模块才能被直接识别导入。
运行逻辑补充:直接运行单个
.py文件时,Python会自动把该文件所在的目录加入sys.path;如果以模块方式启动(例如执行python -m 包名.模块名),则会把执行命令时所在的工作目录加入sys.path。
给定参考信息
项目目录结构:
project ├── __init__.py └── package1 ├── __init__.py ├── subpackage1 │ ├── __init__.py │ └── foo.py └── subpackage2 ├── __init__.py ├── bar.py └── subpackage2A ├── __init__.py └── foo_bar.py project2 ├── __init__.py └── ... ├── __init__.py └── tom.py
foo.py内定义的函数:
def foo_func(): print('in foo.py')
问题1:foo_bar.py中通过绝对导入导入foo.py的foo_func
按照Python项目通用规范,提前将project和project2共同的上级工作目录加入sys.path(即让顶级包project能被Python搜索到),在foo_bar.py中写入以下导入代码即可:
from project.package1.subpackage1.foo import foo_func # 调用示例 if __name__ == '__main__': foo_func() # 执行后输出 in foo.py
说明:绝对导入路径从顶级包project开始逐层写全:project(顶级包)→ package1(二级包)→ subpackage1(三级包)→ foo(目标模块),最终导入目标函数foo_func,是完全符合规范的绝对导入写法。
问题2:bar.py中通过绝对导入导入foo.py的foo_func
绝对导入不关心当前文件所在的目录层级,永远从顶级包路径开始写全路径,在bar.py中写入以下代码即可:
from project.package1.subpackage1.foo import foo_func # 调用示例 if __name__ == '__main__': foo_func() # 执行后输出 in foo.py
踩坑提示:不要因为
bar.py和subpackage1同属package1层级,就简写导入路径为from subpackage1.foo import foo_func。当你直接运行bar.py时,Python会自动把bar.py所在的subpackage2目录加入sys.path,搜索路径下不存在subpackage1,会直接抛出ModuleNotFoundError,必须从顶级包开始写全路径才是合规的绝对导入写法。
问题3:tom.py中是否可以导入foo_bar.py并使用foo_func
默认配置下不可以,完成对应路径配置后可以实现,分情况说明:
- 默认状态:
tom.py归属project2目录,直接运行tom.py时,Python只会把project2相关目录加入sys.path,搜索路径中没有project包的位置,无法识别project下的模块,导入时会直接抛出ModuleNotFoundError。 - 可实现的配置方法:
- 将
project和project2共同的上级根目录加入Python搜索路径,可以通过配置PYTHONPATH环境变量,或者在项目启动脚本中动态追加路径的方式实现 - 路径配置完成后,要保证
foo_bar.py本身的导入语句符合绝对导入规范,否则导入foo_bar时会先执行foo_bar.py的顶层代码触发导入错误 - 配置完成后
tom.py中的导入示例:# 方式1:直接从foo的原始路径导入,最稳妥,不依赖foo_bar的导出逻辑 from project.package1.subpackage1.foo import foo_func # 方式2:从foo_bar导入,前提是foo_bar中已经正确导入并暴露了foo_func from project.package1.subpackage2.subpackage2A.foo_bar import foo_func
- 将
补充说明:跨顶级项目目录的导入不符合Python项目常规设计规范,生产环境不建议使用,最好将公共依赖的模块抽到统一的公共包下,避免跨项目的路径依赖。
内容的提问来源于stack exchange,提问作者Jiho Kim

