文章目录
前言
码python时经常会遇到找不到包或者找不到模块的ModuleNotFoundError报错,为了以后少出现这类问题,今天来学习记录下python中import的索引机制。
一 python中import的索引机制
在码python时我们会因为各种各样的原因遇到ModuleNotFoundError: No module named ‘XXX’ 的报错,这个报错通常是在引用某个包或者模块时报的,是python中新手老手都会遇到的问题。像我这种不是python专业开发但是平时又要用的人来说,遇到此类问题有时候就得花点时间,索性今天来探探其中的缘由。
1. python中import的搜索路径
通过查看python官方手册和网上大佬的博文得知import的搜索路径有两大步骤:先判断import后面的XXX包是不是内置模块,内置模块可以直接import,基本不会报错。如果XXX不是内置的,那么就从sys.path的列表中依次查找XXX,如果遍历完sys.path还找不到XXX就抛ModuleNotFoundError异常结束。其中sys.path对于我们来说才是重点,因为我们平时自建的包不是python内置的,其索引路径一般是加在sys.path列表中的。具体如下
先判断是否内置模块
使用import导入XXX会先判断XXX是否是python内置模块,是内置模块直接import不会报错,除非XXX名字与内置模块命名空间冲突。
根据sys.path查找
1.1 脚本当前目录和所属项目目录
当XXX不是内置模块时,python解释器就会依次遍历sys.path列表中的路径寻找XXX,注意这里是依次遍历,是有先后顺序的。
来看看sys.path列表中都有哪些信息
import sys
import pprint
pprint.pprint(sys.path)
结果如下
上面是在window环境用pycharm打印的sys.path。最前面的两个是分别是:当前远行脚本所在的目录和当前脚本所属的项目所在的目录,但要注意这里的当前脚本所属的项目所在的目录有可能是编辑器自动添加到sys.path的。比如我这里的’D:\python\python-learning’, 就是pycharm自动给添加的(vscode好像不会),如下
但如果你去cmd命令行打印sys.path,就不会自动给你添加项目目录,如下
可以看到在cmd命令行打印的sys.path里面只有当前脚本所在目录,没有脚本所在的项目目录。所以很多时候我们在编辑器里面运行好好的,但在命令行运行却报ModuleNotFoundError异常,就是因为这个。
例如我在pycharm和cmd运行CSDN.py,在pycharm运行不会报错,而cmd运行则会报错,如下
CSDN.py
import sys
import pprint
from 模块和包 import test2
pprint.pprint(sys.path)
print("分割线".center(50, '#'))
test2.test_2()
1.2 环境变量
如果模块在脚本当前目录和所属项目目录都没有找到的话就会通过环境变量去查找。
比如我在E盘E:\python-path有个demo.py,如果我不加环境变量PYTHONPATH,那么其它目录下的脚本import demo就会抛异常。而加了环境变量PYTHONPATH,sys.path列表就会自动添加PYTHONPATH的路径,从而不会报错。如下
未加环境变量PYTHONPATH,报错
添加加环境变量PYTHONPATH,sys.path增加PYTHONPATH的路径,不会抛异常。这里要注意添加PYTHONPATH后要重启pycharm。
1.3 标准库
如果模块通过环境变量没有找到,那么会去python的标准库目录中查找。
1.4 .pth 文件
如果模块在标准库没有被找到,那么会通过.pth文件中的路径继续查找模块。.pth文件的作用和环境变量PYTHONPATH一样,都会把路径加到sys.path。.pth文件要放在python安装目录下的site-package文件下,一行就代表一个路径。
比如我通过.pth来添加E:\python-pth,import 该目录的test.py模块,如下
test.py
def test():
print("this is .pth")
运行结果如下
可以看到sys.path列表中已经添加了E:\python-pth目录,而且成功import 其目录下的test模块。
1.5 第三方库
如果.pth文件里面的目录也找不到模块,那么就会去第三方库目录site-packages查找,如果第三方库还找不到就抛ModuleNotFoundError异常。
1.6 import索引流程图
简单画了个流程,如下
2. 解决ModuleNotFoundError
上面了解了import的索引机制后,再遇到ModuleNotFoundError异常应该就不难解决,不过为列加深印象还是写了一篇,详情请看: 解决python import时ModuleNotFoundError异常