Python脚本导入与模块导入的机制差异及问题解决
Python两种执行方式的导入差异与解决方法
问题背景
文件目录结构:
package1/ p1.py package2/ p2.py
package1/p1.py代码:
def p1fun(): print("p1fun")
package1/package2/p2.py代码:
import package1.p1 if __name__ == '__main__': package1.p1.p1fun()
执行python -m package1.package2.p2时能正常输出p1fun,但执行python package1/package2/p2.py时会报错:
Traceback (most recent call last): File "/home/marcin/projects/test/package1/package2/p2.py", line 1, in <module> import package1.p1 ModuleNotFoundError: No module named 'package1'
一、两种执行场景的导入机制差异
1. 模块模式(python -m package1.package2.p2)
- Python会自动把当前工作目录(也就是
package1所在的上级目录)加入模块搜索路径sys.path的首位。 - 此时
package1被识别为顶层包,package1.p1属于包内的子模块,Python能从搜索路径里找到package1,所以导入成功。 - 脚本以包的一部分身份加载,
__name__被设为__main__,但包结构的层级关系被保留。
2. 脚本模式(python package1/package2/p2.py)
- Python会把脚本所在的目录(即
package1/package2/)加入sys.path的首位。 - 此时Python搜索模块时,只会从
package1/package2/和默认路径查找,找不到上层的package1目录,因此抛出ModuleNotFoundError。 - 脚本作为独立文件执行,不被视为包结构的一部分,上层目录不在搜索范围内。
二、让脚本模式导入正常工作的方法
方法1:动态修改sys.path
在p2.py开头添加代码,手动把package1的父目录加入搜索路径:
import sys import os # 获取当前脚本的绝对路径,再向上两级找到package1的父目录 parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(parent_dir) import package1.p1 if __name__ == '__main__': package1.p1.p1fun()
修改后,无论哪种方式执行都能正常导入。
方法2:使用相对导入(仅兼容模块模式)
把p2.py的导入语句改成相对导入,指向同一包结构内的p1:
from .. import p1 if __name__ == '__main__': p1.p1fun()
注意:这种写法只能在模块模式下运行(python -m package1.package2.p2),直接执行脚本仍会报错——因为相对导入要求模块必须是包的一部分,而脚本模式下模块不属于任何包。
方法3:设置PYTHONPATH环境变量
执行脚本前,把package1所在的父目录添加到PYTHONPATH:
- Linux/macOS终端:
export PYTHONPATH=/path/to/package1的父目录:$PYTHONPATH python package1/package2/p2.py
- Windows命令提示符:
set PYTHONPATH=C:\path\to\package1的父目录;%PYTHONPATH% python package1/package2/p2.py
设置后,Python会自动把该目录加入模块搜索路径,无需修改代码。
内容的提问来源于stack exchange,提问作者Marcin
相关产品推荐
相关产品推荐

