前言
通过制作简易的demo,让其更加深入的了解如何使用
1. 问题所示
发现python的同级目录相互调用会出bug
e:\software\anaconda3\envs\py3.10\python.exe f:\python_project\test\father\child\file3.py traceback (most recent call last): file "f:\python_project\test\father\child\file3.py", line 1, infrom ..file1 import greet # 这将失败,没有 __init__.py importerror: attempted relative import with no known parent package process finished with exit code 1
截图如下:
2. 原理分析
出现 importerror: attempted relative import with no known parent package 错误的原因是 python 无法识别当前脚本的父包,因此相对导入失败
要解决这个问题并理解其背后的原理,需要了解以下几点:
原理分析
相对导入的限制:
相对导入(例如,from …module import something)只能在包(包含 __init__.py
文件的目录)中使用
当运行脚本时,如果它所在的包没有正确识别,python无法解析相对导入
脚本直接运行的问题:
如果直接运行一个脚本(例如,通过 python file3.py),该脚本的包上下文不会被识别
相对导入会失败,因为python不知道如何定位脚本的父包
3. 解决方法
先给一个demo
其文件结构如下:
test/ ├── father/ │ ├── file1.py │ └── child/ │ └── file3.py
file1如下:
def greet(): print("hello from file1")
file3如下:
from ..file1 import greet # 这将失败,没有 __init__.py def main(): greet() if __name__ == "__main__": main()
这将执行出错
通用的解决方式有如下:
3.1 添加父目录
在file3中修改代码为如下:
import sys import os # 将父目录添加到 sys.path sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from father.file1 import greet def main(): greet() if __name__ == "__main__": main()
执行的结果如下:
3.2 相对路径
修改file3如下:
from ..file1 import greet def main(): greet() if __name__ == "__main__": main()
但是 执行结果如下:
需要使用命令行的方式来执行:
注意差异
如果file3的文件如下:
from father.file1 import greet def main(): greet() if __name__ == "__main__": main()
还是可以直接运行的:
3.3 添加init
截图如下:
对应file3的文件如下:
from father.file1 import greet def main(): greet() if __name__ == "__main__": main()
截图如下:
也可使用命令行的方式来执行:
__init__.py
文件在 python 3.3 及其之后的版本中不是必须的,但它有助于将目录标识为一个包