今天在公衆號粉絲羣裏面,有一位同窗提到了 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
中。
各位,當你寫代碼的時候,你先想想,若是別人拿到了你的代碼,想要梳理一下這個項目的邏輯,在不詢問你的狀況下,怎麼讓他知道應該從哪一個文件開始讀?應該按什麼順序讀?他能不能輕易地看到數據在你的代碼中是怎麼運轉的?