ccran 的个人博客 ccran 的个人博客

记录精彩的程序人生

目录
Python自建模块导入规范
/  

Python自建模块导入规范

Python自建模块导入规范

近期,在Python项目中导入自己写的模块时,时而会出现ModuleNotFoundError的异常。

当然,异常主要还是在直接通过Python命令执行py文件的时候出现(部署),在IDE工具中则出现较少(开发)。

究其本质还是需要理解Python解释器是通过sys.path来寻找模块。

通过建立一个demo来记录后续Python开发时自建包的导入规范。

一、demo

demo结构如下图所示:demo由自己写的main模块以及module模块组成。

项目路径为 F:\PycharmProject\SelfBuildModuleDemo

demoStructure.png

a.py:代码打印简单字符串

def func_a():
    print("func_a")

b.py:代码打印sys.path,提供func_b方法,并访问a.py中的func_a

import sys
from a import func_a

def func_b():
    print("func_b")

if __name__ == '__main__':
    print(sys.path)
    func_a()
    func_b()

main.py:代码打印sys.path,访问a.py和b.py

import sys
print(sys.path)

from module.a import func_a
from module.b import func_b

if __name__ == '__main__':
    func_a()
    func_b()

二、分析

2.1 直接通过Python解释器执行

首先通过Python解释器执行b.py和main.py

执行b.py:正常执行

F:\PycharmProject\SelfBuildModuleDemo\module
λ python b.py
['F:\\PycharmProject\\SelfBuildModuleDemo\\module', 
'D:\\Anaconda\\python37.zip', 'D:\\Anaconda\\DLLs', 
'D:\\Anaconda\\lib', 'D:\\Anaconda', 
'D:\\Anaconda\\lib\\site-packages', 
'D:\\Anaconda\\lib\\site-packages\\win32', 
'D:\\Anaconda\\lib\\site-packages\\win32\\lib',
 'D:\\Anaconda\\lib\\site-packages\\Pythonwin']
func_a
func_b

Python解释器执行时,会将所执行py文件的所在的目录加入sys.path作为list的第一个元素.

结合 F:\PycharmProject\SelfBuildModuleDemo\modulefrom a import func_a 自然可以找到module目录下的a.py文件

执行main.py:提示module模块没找到

显然,因为 F:\PycharmProject\SelfBuildModuleDemo\main 目录下没有module模块

F:\PycharmProject\SelfBuildModuleDemo\main
λ python main.py
['F:\\PycharmProject\\SelfBuildModuleDemo\\main',
 'D:\\Anaconda\\python37.zip', 
'D:\\Anaconda\\DLLs', 'D:\\Anaconda\\lib', 
'D:\\Anaconda', 'D:\\Anaconda\\lib\\site-packages',
 'D:\\Anaconda\\lib\\site-packages\\win32', 
'D:\\Anaconda\\lib\\site-packages\\win32\\lib',
 'D:\\Anaconda\\lib\\site-packages\\Pythonwin']
Traceback (most recent call last):
  File "main.py", line 6, in <module>
    from module.a import func_a
ModuleNotFoundError: No module named 'module'

因此将 F:\PycharmProject\SelfBuildModuleDemo 加入sys.path

sys.path.append("F:\\PycharmProject\\SelfBuildModuleDemo")

再次执行main.py:提示a模块找不到(最大坑点)

F:\PycharmProject\SelfBuildModuleDemo\main
λ python main.py
['F:\\PycharmProject\\SelfBuildModuleDemo\\main', 
'D:\\Anaconda\\python37.zip', 'D:\\Anaconda\\DLLs',
 'D:\\Anaconda\\lib', 'D:\\Anaconda',
 'D:\\Anaconda\\lib\\site-packages', 
'D:\\Anaconda\\lib\\site-packages\\win32', 
'D:\\Anaconda\\lib\\site-packages\\win32\\lib',
 'D:\\Anaconda\\lib\\site-packages\\Pythonwin', 
'F:\\PycharmProject\\SelfBuildModuleDemo']
Traceback (most recent call last):
  File "main.py", line 7, in <module>
    from module.b import func_b
  File "F:\PycharmProject\SelfBuildModuleDemo\module\b.py", line 2, in <module>
    from a import func_a
ModuleNotFoundError: No module named 'a'

可以发现,是由于我们在导入b.py时是通过import a来进行导入的,但是我们的路径sys.path下还是没有a模块。我们只能将F:\PycharmProject\SelfBuildModuleDemo\module加入sys.path。

最终终于可以在命令行通过Python解释器成功执行main.py了。😄

2.2 通过Pycharm执行

执行b.py:可以看见b.py文件是有报错信息的,但是我们依旧可以正常执行。

与直接通过Python解释器执行相比,Pycharm里面的Python解释器将项目的根目录配置到了sys.path中,还有Pycharm自己的一些额外路径。

['F:\\PycharmProject\\SelfBuildModuleDemo\\module', 
'F:\\PycharmProject\\SelfBuildModuleDemo', 
'D:\\PyCharm 2019.3.3\\plugins\\python\\helpers\\pycharm_display', 'D:\\Anaconda\\envs\\py3.7\\python37.zip', 
'D:\\Anaconda\\envs\\py3.7\\DLLs',
 'D:\\Anaconda\\envs\\py3.7\\lib', 'D:\\Anaconda\\envs\\py3.7', 'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages',
 'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages\\win32', 
'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages\\win32\\lib', 'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages\\Pythonwin',
 'D:\\PyCharm 2019.3.3\\plugins\\python\\helpers\\pycharm_matplotlib_backend']
func_a
func_b

执行main.py:出现a模块没有找到的异常。显然是因为module目录没在sys.path中。

['F:\\PycharmProject\\SelfBuildModuleDemo\\main', 
'F:\\PycharmProject\\SelfBuildModuleDemo', 
'D:\\PyCharm 2019.3.3\\plugins\\python\\helpers\\pycharm_display', 'D:\\Anaconda\\envs\\py3.7\\python37.zip', 'D:\\Anaconda\\envs\\py3.7\\DLLs', 'D:\\Anaconda\\envs\\py3.7\\lib', 'D:\\Anaconda\\envs\\py3.7', 'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages',
 'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages\\win32', 
'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages\\win32\\lib', 'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages\\Pythonwin',
 'D:\\PyCharm 2019.3.3\\plugins\\python\\helpers\\pycharm_matplotlib_backend']
Traceback (most recent call last):
  File "F:/PycharmProject/SelfBuildModuleDemo/main/main.py", line 6, in <module>
    from module.b import func_b
  File "F:\PycharmProject\SelfBuildModuleDemo\module\b.py", line 2, in <module>
    from a import func_a
ModuleNotFoundError: No module named 'a'

这时,我们在Pycharm中,将module目录标记为Sources(标记为蓝色),成功执行。😃

分析得到,是将module目录加入了sys.path中,大概这就是IDE吧~

['F:\\PycharmProject\\SelfBuildModuleDemo\\main', 
'F:\\PycharmProject\\SelfBuildModuleDemo', 
'F:\\PycharmProject\\SelfBuildModuleDemo\\module',
 'D:\\PyCharm 2019.3.3\\plugins\\python\\helpers\\pycharm_display', 'D:\\Anaconda\\envs\\py3.7\\python37.zip', 'D:\\Anaconda\\envs\\py3.7\\DLLs', 'D:\\Anaconda\\envs\\py3.7\\lib', 'D:\\Anaconda\\envs\\py3.7', 'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages', 'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages\\win32', 'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages\\win32\\lib', 'D:\\Anaconda\\envs\\py3.7\\lib\\site-packages\\Pythonwin', 'D:\\PyCharm 2019.3.3\\plugins\\python\\helpers\\pycharm_matplotlib_backend']
func_a
func_b

三、总结

  1. Python解释器通过sys.path来找module
  2. 导包规范:其他包的导入以项目根路径作为基路径进行导入,从而减少在代码中进行sys.path的添加。
  3. 为了部署的时候更方便,可在部署的时候将项目根路径写入PYTHONPATH环境变量。
  4. 了解本质很重要!😊

标题:Python自建模块导入规范
作者:ccran
地址:https://ccran.online/articles/2020/04/28/1588084519546.html