首頁>技術>

今天在粉絲群裡面,有一位同學提到了 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,清理無效資料,那麼此時,我可以在根目錄單獨建立一個script或tools或者bin資料夾,然後把工具指令碼放進去,例如:

在這個工具腳本里面,你可能會呼叫models/mongo-util/mongob_helper.py檔案中的某個函式。這種情況下,你呼叫父資料夾中的內容是可以接受的。但這畢竟只是工具指令碼。

可能還有同學要問,那如果我的專案是一個 Python 的包,它本身沒有入口檔案怎麼辦呢?這個時候,你可以把這個包的__init__.py當做它的入口檔案。大家可以參考我在 GitHub - kingname/GeneralNewsExtractor: 新聞網頁正文通用抽取器 Beta 版.的程式碼組織結構。在專案根目錄留下一個example.py檔案,用來演示如何呼叫這個包。而這個包本身的程式碼,是在一個叫做gne的資料夾中的。這個gne資料夾是一個包,它的入口檔案在__init__.py中。

各位,當你寫程式碼的時候,你先想一想,如果別人拿到了你的程式碼,想要梳理一下這個專案的邏輯,在不詢問你的情況下,怎麼讓他知道應該從哪個檔案開始讀?應該按什麼順序讀?他能不能輕易地看到資料在你的程式碼中是怎麼運轉的?

28
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • AdaBoost演算法:功能強大,但有一個有趣的侷限性