python如何使用import引入其他目录文件或自定义模块
作者:雪的期许
这篇文章主要介绍了python如何使用import引入其他目录文件或自定义模块方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
问题描述
在python工程中,常常需要使用import引入自己编写的其他模块,但其它模块有时不在同一个文件夹下。
此时直接import会导致找不到包而报错
ModuleNotFoundError: No module named '****'
下面提供2种解决方案。
解决方案
以下面的项目结构为例进行说明。
方案1:使用相对路径(局限)
在import时直接使用相对路径
.
代表当前文件所在路径..
代表当前文件的父目录...
代表爷爷目录,以此类推,每多一个点,就向上翻一层目录。
例1,在f1.py
中写:
from ..p2 import f2.py
例2,在t1.py
中写:
from ..b import t2.py
这样写能否执行成功,取决于主函数入口(即你执行的文件)!记住这个原则(局限):
相对路径所涉及的目录范围内不允许有主函数入口
不满足这个原则时,报错
ValueError: attempted relative import beyond top-level package
在上面的项目结构中,如果我们执行python main.py
,那么在main.py
中引入t1.py
会报错,
原因是t1.py
中使用相对引入时,..
回退到的目录是项目主目录,也就是main.py
所在的目录,违反了该原则。
但在main.py
中引入f1.py
是正确的,因为f1.py
在使用相对路径引入时最多回退到pkg
文件夹,不会影响main.py
的执行。
方案2:绝对路径引入(推荐)
1. 在main.py中调用t1.py
这个很常规,直接在main.py
使用import
即可
form a.t1 import *
2. 在t1.py中调用main.py
在t1.py
中写:
import sys from pathlib import Path sys.path.append(str(Path(__file__).resolve().parents[1])) # 将父级目录加入执行目录列表 from main import * # 由于main.py所在目录已加入到sys.path,可直接引入
代码中parents
返回一个列表,parents[0]
代表该文件所在目录,下标每加一,目录向上一层,所以这里parents[1]
得到的是父目录。
3. 几个坑
1. os.getcwd()
- 这个函数获取的始终是当前终端所在目录。
- 例如我的终端现在处在
/home/code/
下,执行python a/1.py
,文件1.py
中的语句os.getcwd()
返回值为/home/code/
。
2. __file__
- 当前文件相对于终端的路径。
- 例如我的终端现在处在
/home/code/
下,执行python a/1.py
,文件1.py
中的语句__file__
返回值为a/1.py
。 - 使用
os.path.abspath(__file__)
可获得该文件的绝对路径/home/code/a/1.py
。 - Tips:拼接路径
os.getcwd()
/__file__
就是该文件的完整绝对路径。
3. sys.path[0]
- 直接运行py文件,即
python xxx.py
时,为执行文件所在的绝对目录(不管终端处于什么路径)。 - 需要注意,若执行
python 1.py
,而1.py
中又import了其他目录的2.py
,那么2.py
的sys.path[0]
与1.py
中相等,也就是说在import其他文件时,其他文件的sys.path[0]
将以当前被执行的文件为准。 - 以模块运行时,即
python -m xxx
时,为终端所在绝对目录,等于os.getcwd()
。
4. 小结
- 在
.py
文件中,使用__file__
最保险。 - 但是在
.ipynb
文件中不存在__file__
变量,怎么办? - 由于
.ipynb
文件一般不考虑被其他文件import
,因此直接使用sys.path[0]
取得文件所在目录即可。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。