今天在公众号粉丝群里面,有一位同窗提到了 Python 找不到模块的问题:python
问题涉及到的代码结构和代码截图以下:git
这个问题的解决方法很是简单,就是把start.py
文件从bin
文件夹移出来就行了。github
但若是对这个问题进一步分析,能够看到更多问题。编辑器
在我之前的文章:为何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
文件夹。spa
若是仅仅从技术上来讲,你非要导入 bin
文件夹的父文件夹下面的其余模块,也并不困难,我在一日一技:导入父文件夹中的模块并读取当前文件夹内的资源一文中讲到了具体的作法。code
但问题在于,你不该该这样作。你不该该把项目的入口文件,放到项目内部很深的文件夹中。orm
所谓入口文件,就是要首先通过它,才能到达其余的文件。当你拿到一个 Python 项目,你只须要首先从入口文件开始阅读代码,根据入口文件调用的模块,一路看下去,你就能读到它的全部实现逻辑。server
但若是你们常常逛 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,清理无效数据,那么此时,我能够在根目录单首创建一个script
或tools
或者bin
文件夹,而后把工具脚本放进去,例如:
在这个工具脚本里面,你可能会调用models/mongo-util/mongob_helper.py
文件中的某个函数。这种状况下,你调用父文件夹中的内容是能够接受的。但这毕竟只是工具脚本。
可能还有同窗要问,那若是个人项目是一个 Python 的包,它自己没有入口文件怎么办呢?这个时候,你能够把这个包的__init__.py
当作它的入口文件。你们能够参考我在 GitHub - kingname/GeneralNewsExtractor: 新闻网页正文通用抽取器 Beta 版.的代码组织结构。在项目根目录留下一个example.py
文件,用来演示如何调用这个包。而这个包自己的代码,是在一个叫作gne
的文件夹中的。这个gne
文件夹是一个包,它的入口文件在__init__.py
中。
各位,当你写代码的时候,你先想想,若是别人拿到了你的代码,想要梳理一下这个项目的逻辑,在不询问你的状况下,怎么让他知道应该从哪一个文件开始读?应该按什么顺序读?他能不能轻易地看到数据在你的代码中是怎么运转的?