赞
踩
目录
Python本地模块的引入是比较简单的,包括绝对引用和相对引用(相对引用的博客参考下一篇Python基础 - 本地模块的相对导入/引用),个人比较推荐使用绝对引用,会避免掉很多错误,本篇文章主要介绍绝对导入。
项目入口文件一般要放在项目根目录下,如下图1红框main.py所示,即为项目入口文件。如果运行main.py,系统会自动把入口文件所在的根目录,加入到sys.path里。这样在以引用方式导入包时,会逐一查找sys.path中的路径,第一个即为项目根目录,如下图2所示,其中sys.path的路径包括:[项目根目录。python的压缩包路径。python自带的一些库如os, json等。so库文件。使用pip/conda安装时的第三方库]
绝对导入是比较简单的,也比较推荐大家采用这种方式。首先根据上图画出当前的文件树,如下:
- Import_Test
- |--dir1
- |--d11.py
- |--d12.py
- |--dir2
- |--d21.py
- |--d22.py
- |--test.py
首先我们明确一点的是,如果运行哪个文件,该文件所在的父目录就会被加载到sys.path中,在绝对导入模块时就以这个父目录为依据来查找文件夹/文件
示例1:引入入口文件的同级目录文件
- # test.py ----------------------------
- from dir1.d11 import d11_f
-
- def test_f():
- print("test")
-
- if __name__ == '__main__':
- test_f()
- d11_f()
-
- # dir1/d11.py ------------------------
- def d11_f():
- print("d11_f")
-
- # 运行结果如下:
- (base) @118:~/Wmq/Import_Test$ python test.py
- test
- d11_f
从层级上看,test.py在根目录下,所以在运行时,test.py的父目录/Wmq/Import_Test被加载到sys.path中,所以引用dir1下的d11模块时,直接引用dir1,因为该目录在/Wmq/Import_Test下。
示例2:test.py没变,引入的子模块dir1.d11同时引入同级模块dir1.d12
- # test.py ----------------------------
- from dir1.d11 import d11_f
-
- def test_f():
- print("test")
-
- if __name__ == '__main__':
- test_f()
- d11_f()
-
- # dir1/d11.py ------------------------
- from dir1.d12 import d12_f
-
- def d11_f():
- print("d11_f")
- d12_f()
-
- # dir1/d12.py ------------------------
- def d12_f():
- print("d12_f")
-
- # 运行结果如下:
- (base)@118:~/Wmq/Import_Test$ python test.py
- test
- d11_f
- d12_f
同级模块的引入是比较好理解的,根据示例1,test.py在运行时,其父目录/Wmq/Import_Test被加载到sys.path中,所以无论怎么调用d12_f,都要在/Wmq/Import_Test的基础上引入,而dir1就在盖目录下,所以就是dir1.d12。
示例3:test.py没变,引入的子模块dir1.d11同时引入跨文件夹模块dir2.d21
- # dir1/d11.py ------------------------
- from dir2.d21 import d21_f
- def d11_f():
- print("d11_f")
- d21_f()
-
- # dir2/d21.py ------------------------
- def d21_f():
- print("d21_f")
-
- # 运行结果如下:
- (base)@118:~/Wmq/Import_Test$ python test.py
- test
- d11_f
- d21_f
从示例不难发现,在dir1文件下的d11.py中,是如何跳跃文件夹引入dir2文件下的d21.py呢?是直接导入dir2文件夹。为什么这样不报错,原因也在示例1/2中有解释,test的运行加载了父目录/Import_Test,而dir2就在父目录下,所以直接引入dir2即可。
示例4:如果不运行test.py了,只运行dir1/d11.py, 其他任何引用不变,结果如下:
- # dir1/d11.py -------------------
- from dir2.d21 import d21_f
-
- def d11_f():
- print("d11_f")
- d21_f()
-
- if __name__ == '__main__':
- d11_f()
-
- # 运行结果报错,如下:
- (base) zhangyujun@118:~/Wmq/Import_Test/dir1$ python d11.py
- Traceback (most recent call last):
- File "d11.py", line 1, in <module>
- from dir2.d21 import d21_f
- ModuleNotFoundError: No module named 'dir2'
运行报错了,这其实在情理之中。因为我们前面说过,如果运行哪个文件,该文件所在的父目录就会被加载到sys.path中,在绝对导入模块时就以这个父目录为依据来查找文件夹/文件。那当我们运行d11.py时,d11.py的父目录也就是dir1被加载到sys.path中,然后顺着dir1往下找,肯定找不到dir2的,所以报错。我们验证下sys.path看一下是不是dir1被加载进去了,如下:
- # dir1/d11.py -------------------
- import sys
- print(sys.path)
-
- from dir2.d21 import d21_f
- def d11_f():
- print("d11_f")
- d21_f()
-
- if __name__ == '__main__':
- d11_f()
-
- # 运行结果:
- (base) zhangyujun@118:~/Wmq/Import_Test/dir1$ python d11.py
- ['/home/zhangyujun/Wmq/Import_Test/dir1',
- '/home/zhangyujun/anaconda3/lib/python38.zip',
- '/home/zhangyujun/anaconda3/lib/python3.8',
- '/home/zhangyujun/anaconda3/lib/python3.8/lib-dynload',
- '/home/zhangyujun/anaconda3/lib/python3.8/site-packages']
-
- Traceback (most recent call last):
- File "d11.py", line 3, in <module>
- from dir2.d21 import d21_f
- ModuleNotFoundError: No module named 'dir2'
确实,sys.path中的第一个是dir1目录,自然找不到dir2目录,那怎么解决这种问题呢?我们可以在sys.path里添加上根目录,运行结果即可正常,如下:
- # dir1/d11.py -------------------
- import sys
- sys.path.append("/home/zhangyujun/Wmq/Import_Test")
-
- from dir2.d21 import d21_f
- def d11_f():
- print("d11_f")
- d21_f()
-
- if __name__ == '__main__':
- d11_f()
-
- # 运行结果:
- (base)@118:~/Wmq/Import_Test/dir1$ python d11.py
- d11_f
- d21_f
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。