明天在公众号粉丝群外面,有一位同学提到了 Python 找不到模块的问题:

问题波及到的代码构造和代码截图如下:

这个问题的解决办法非常简单,就是把start.py文件从bin文件夹移出来就好了。

但如果对这个问题进一步剖析,能够看到更多问题。

在我以前的文章:为什么Python代码能运行然而PyCharm给我画红线?中,我讲到了工作区(Workdir)对代码的影响。PyCharm、VSCode 辨认的工作区,可能并不等于你间接在终端窗口运行.py文件时候的工作区。

明天这个问题实质上也是工作区导致的问题。 这个同学的我的项目根目录是MY_API,所以他应用的编辑器VSCode 就会默认把MY_API当做工作区。所以,当他在start.py文件中写上from lib.interface import server时,VScode 并不会给他标记红色波浪线。因为从 VSCode 的视角看,lib文件夹的确就是在工作区上面的。

然而,当他在 VSCode 外面运行这个start.py文件时,Python 是从bin文件夹上面运行的。此时,Python 会把bin文件夹当做工作区。在工作区外面就只有这一个start.py文件,所以当然找不到lib文件夹。

如果仅仅从技术上来说,你非要导入 bin 文件夹的父文件夹上面的其余模块,也并不艰难,我在一日一技:导入父文件夹中的模块并读取以后文件夹内的资源一文中讲到了具体的做法。

但问题在于,你不应该这样做。你不应该把我的项目的入口文件,放到我的项目外部很深的文件夹中。

所谓入口文件,就是要首先通过它,能力达到其余的文件。当你拿到一个 Python 我的项目,你只须要首先从入口文件开始浏览代码,依据入口文件调用的模块,一路看上来,你就能读到它的所有实现逻辑。

但如果大家常常逛 Github,就会发现,有些人可能是被其余垃圾语言净化了思维,他的 Python 我的项目,根目录有五六个文件夹和七八个.py文件。你拿到这个我的项目的时候,你甚至不晓得,当你想运行这个代码的时候,python3 xxx.py应该运行哪个文件。你多方打听,或者看了半天文档,才晓得,哦,原来入口文件在com/xx/yy/zz/script/run.py

当你关上这个run.py文件,你发现它的顶部,文件导入的代码写的是from ../../../../aaa import bbb

几乎是神经病写法。我晓得有些垃圾语言风行这样写。但当初你用的是 Python,学聪慧一点,别那样写。

对于一个 Python 我的项目来说,入口文件应该始终在最外层。例如:

当你要启动这个我的项目的时候,间接在最外层python3 main.py,就能把它启动起来。在main.py外面,你能够导入其余模块,而后调用其余模块外面的类或者函数。

这样做的益处是什么?这样做,你是在我的项目的根目录启动的这个我的项目,所以你的工作区就是我的项目的根目录。那么你在任何一个.py文件外面都能够很容易地基于工作区导入任意其余文件。例如,你当初在models/mongo-util/mongob_helper.py文件中,你想导入utils/abc.py中的time_format()函数,那么,你只须要这样写就能够了。

from utils.abc import time_format

你基本不可能呈现须要导入父文件夹中的某个模块的状况。

只有工具脚本,才须要独自应用一个文件夹来寄存,而后调用父文件夹中的其余文件。例如,我当初有一个工具脚本,它每天晚上0点会读写 MongoDB,清理有效数据,那么此时,我能够在根目录独自创立一个scripttools或者bin文件夹,而后把工具脚本放进去,例如:

在这个工具脚本外面,你可能会调用models/mongo-util/mongob_helper.py文件中的某个函数。这种状况下,你调用父文件夹中的内容是能够承受的。但这毕竟只是工具脚本。

可能还有同学要问,那如果我的我的项目是一个 Python 的包,它自身没有入口文件怎么办呢?这个时候,你能够把这个包的__init__.py当做它的入口文件。大家能够参考我在 GitHub - kingname/GeneralNewsExtractor: 新闻网页注释通用抽取器 Beta 版.的代码组织构造。在我的项目根目录留下一个example.py文件,用来演示如何调用这个包。而这个包自身的代码,是在一个叫做gne的文件夹中的。这个gne文件夹是一个包,它的入口文件在__init__.py中。

各位,当你写代码的时候,你先想一想,如果他人拿到了你的代码,想要梳理一下这个我的项目的逻辑,在不询问你的状况下,怎么让他晓得应该从哪个文件开始读?应该按什么程序读?他能不能轻易地看到数据在你的代码中是怎么运行的?