1. 程式人生 > >python專案內import其他內部package的模組的正確方法

python專案內import其他內部package的模組的正確方法

本文主要介紹如何在一個Python專案中,優雅的實現專案內各個package的模組(module)之間的相互引用。

之所以寫這篇文章,是因為網上流傳的各種奇技淫巧簡直五花八門(包括stackoverflow等知名社群),極易誤導對python的import機制不熟悉的人。比如我就曾一度因為找不到優雅的import方式,而認為python是一門愚蠢的語言。所以,我把近一上午的學習結果總結出來,希望大家不要誤入歧途。

本文參考瞭如下兩篇部落格: 
habnab關於python package的精彩總結:地址點我 
Jean-Paul Calderone關於python專案結構的建議:地址點我

demo project

本文以一個demo project為例,來介紹python的包管理機制。

這個demo project我放到github上了:地址點我

其中,專案根目錄有三個資料夾:

  • data:存放專案資料
  • doc:存放專案文件
  • package:一個demo python package

其中,package中的檔案結構如下圖: 
專案結構

python package

基礎知識

當你import的時候,python只會在sys.path這個變數(一個list,你可以print出來看)裡面的路徑中找可能匹配的package和module。

而一個package跟一個普通資料夾的區別在於,package的資料夾中多了一個__init__.py檔案。換句話說,如果你在某個資料夾中添加了一個__init__.py檔案,則python就認為這個資料夾是一個package。

__init__.py檔案可以是空的(也推薦者這麼做),它只是告訴python當前資料夾是一個package。當然,也可以在裡面新增一些程式碼,這些程式碼會在import這個包的時候執行。

所以,請確保你要import的檔案所在的資料夾有__init__.py檔案(除非它在sys.path中某個資料夾下)。

錯誤的import做法

如上述project中,如果你想讓subpackage2中的foo2來import subpackage1中的foo1,便會出現找不到subpackage1的情況。

目前網路上大部分的做法都是通過sys.path.append(yourpath)之類的方法,將你需要import的module的目錄新增到sys.path中。或者,通過修改PYTHONPATH這個環境變數來將新增(跟修改sys.path效果相同)。

但是,這種做法有如下幾個缺點:

  • 如果你用PYTHONPATH,那麼當有多個專案時,你需要把每個專案的根目錄都加入到PYTHONPATH中,會使得PYTHONPATH變得十分臃腫
  • 如果你使用sys.path,由於資料夾是動態新增的,所以當你使用相對路徑的時候,實際路徑會十分依賴於你的入口函式,當入口函式改變很可能就會導致程式碼無法執行
  • 如果你使用絕對路徑,將你的程式碼在其他機器上執行的時候需要重新配置這些變數,十分麻煩

正確的做法

程式碼中正常import

首先,在程式碼中按照正常方式匯入你需要的包

比如,你需要在app.py中匯入foo1,則:

from package.subpackage1 import foo1 

雖然你可能發現from subpackage1 import foo1也可以正常執行,但是請避免這種使用相對路徑的方法。因為這在python3中將不再支援,同時也有可能會引起奇怪的問題。同時,雖然PEP 328中也給出了 from .subpackage1 import foo1這樣的形式,但是還是不要自己給自己製造麻煩,統一使用完整路徑(絕對路徑)為好。

再比如,如果你需要在foo2.py中匯入foo1.py(在不同的subpackage中),則:

from package.subpackage1 import foo1

跟上面一模一樣,這就是使用絕對路徑的好處,各處的引用高度統一。同時,如果你的package被安裝在其他使用者的機器中,其他使用者也會使用這種絕對路徑來import你package中的模組(回想你自己import第三方package的情景)。

建立__main__.py檔案

在package的根目錄中建立__main__.py檔案,可以使得你的package可以通過python -m直接執行。

demo中的__main__.py檔案十分簡單:

from package.app import main

main()


即import真正的主函式app.py中的main方法,然後呼叫main()

用python -m執行你的python檔案

python的-m引數官方說法是: 
Searches sys.path for the named module and runs the corresponding .py file as a script.

在下面的例子中,加上-m引數後,所執行的.py檔案便會識別其頂層的package

回到剛才的例子。建立完__main__.py之後,cd到專案的根目錄,執行

python -m package

即可實現直接執行__main__.py,即直接運行了package這個包

如果你想直接執行package內的某個.py檔案,比如foo1,則:

python -m package.subpackage1.foo1


當然,你要確保foo1中存在判斷其是否是入口函式的邏輯,如下:

if __name__ == "__main__":

    speak()

總結

至此,我們已經實現了你所希望的所有功能:

  • 在project內部實現各個模組之間的import
  • project中的各個.py檔案可以直接執行
  • 將project遷移到其他機器時,不用進行額外配置

如果還有不明白的,可以將github上的原始碼下載下來看一看,然後用python -m執行一下

相關推薦

python專案import其他內部package模組正確方法

本文主要介紹如何在一個Python專案中,優雅的實現專案內各個package的模組(module)之間的相互引用。 之所以寫這篇文章,是因為網上流傳的各種奇技淫巧簡直五花八門(包括stackoverflow等知名社群),極易誤導對python的import機制不熟悉的人

PyCharm專案import其他內部package模組正確方法

最近從svn上下載了一個專案程式碼,使用PyCharm打開出現了很多的錯誤提示:No module named ***;之前遇到這個問題都是直接用pip install *** 解決,但是這次倒入的都是專案內部的模組,程式碼也沒錯,不知道為啥還會提示錯誤。後來問了同事前輩,才

python中怎麼import自己寫的模組

最近在接觸學習ML的一些東西,看了Androw 的視訊和deep learning的東西,正在看PRML這本入門的好書,接下來也想記錄自己的學習心得。 另外也希望找一本能夠對著碼碼程式碼,實現些東西的書,就找到了 Machine Learning in Action 這麼一

python專案實戰:獲取電腦中的磁碟資訊方法

前言 外部儲存器中也採用了類似磁帶的裝置,比較常用的一種叫磁碟,將圓形的磁性碟片裝在一個方的密封盒子裡,這樣做的目的是為了防止磁

python小白使用pycharm新建專案import什麼建包都報錯

第一次使用pycharm建立python專案,本來以為建立很簡單,但是新建.py專案之後,發現import什麼內建包都報錯:no module 明明已經使用pip工具安裝了。 後面才發現是需要設定的:python執行程式碼的話需要python解析器,然而在pycharm中

python在windows下import其他模組的注意事項

初學python,在同一目錄中建立了兩個py檔案:a.py和b.py,然後在a.py中import b.py from . import b ...... 在linux下執行沒有問題,但是在windows下就提示  ImportError: cannot import

Python Import機制備忘-模組搜尋路徑(sys.path)、巢狀Importpackage Import

最近在看《Python原始碼剖析》,對Python內部執行機制比以前瞭解的更深入了,感覺自己有機會也可以做個小型的動態指令碼語言了,呵呵,當然是吹牛了。目的當然不是創造一個動態語言,目的只有一個:更好的使用Python。看到模組匯入那塊的時候,終於對模組匯入機制比較瞭解了,以

python相對包導入報“Attempted relative import in non-package”錯誤

package 相對 swe 部分 nth 位置 .com str 例子 在python當中使用相對包導入有的時候是一件非常讓人痛苦的事情,有的時候使用了相對包導入明明可以在運行,但是換了一種運行方式又不可以了。這篇文章就要深度的解決這個問題,在看的過程要不斷的敲代碼來

Python建包】csv模組用法

一、概述 CSV(逗號分隔符)檔案是表格與資料庫操作之中最常用的輸入輸出格式。在RFC4180中的檔案描述標準對CSV格式進行規範之前,CSV格式檔案就已經被應用了很多年了。而缺乏合適的格式描述規範意味著不同應用的輸入輸出格式會有著細微的差別。因此在從不同源生成這些檔案的時候,這些差別相

如何將python專案部署到其他沒有安裝python環境的電腦

首先安裝pyinstaller 命令pip3 install pyinstaller 到專案要執行的程式碼的那個.py檔案(例如testPyinstaller.py),右鍵copy path, (例如我的是D:\workspaceForPy\testPyinstaller\.idea\t

Python模組struct學習筆記

python處理二進位制資料時可以使用python的struct模組。 struct模組中最重要的三個函式是pack(), unpack(), calcsize(): pack(fmt, v1, v2, ...)     按照給定的格式(fmt),返回一個包裝後的字串。

Python 專案依賴模組管理(自動生成requirements.txt和安裝)

首先,建議初學者每個專案用單獨的env,否則用這種方式收集依賴會把你本地的所有模組版本都匯出來,env的建立,我上一個帖子有。 1. 匯出env中的模組到requirements.txt pip freeze > requirements.txt 2.安裝已有requir

Python模組詳解

一、什麼是模組   模組就是封裝了一些列功能的py檔案,我們使用的時候直接匯入這個檔案,通過傳入引數的方式使用其他檔案的功能函式 二、模組有哪些 內建模組 自定義模組 第三方模組 三、如何匯入模組   匯入模組分為4種: 1 #匯入模組 2 import mode_tes

python通過模組監控磁碟、記憶體、CPU、負載

01. 概述 閒來無事幹,說幹就幹。主要是通過python函式以及python內建模組來實現對磁碟、記憶體、CPU、負載的資料採集,然後傳送到企業號,併到達微信端,方便檢視資訊。 指令碼存放於gitlab上:python監控原文地址:https://www.mairoot.com/?p=1708 02.

python基礎模組相關

python內建函式:compile() 描述 compile() 函式將一個字串編譯為位元組程式碼。 語法 以下是 compile() 方法的語法: compile(source, filename, mode[, flags[, dont_inherit]]) 引數

python中的import模組引用(二)

我們可以使用from import來將指定模組裡所有變數(包含變數名)匯入進來  #繼續採用上面的路徑# from first.first_1.a1 import * print (a + b * c - d + e * f)   如果不想引用模組的所有變數,可以

python中的import模組引用(一)

python利用import匯入模組來實現程式碼的高複用性。 在同一個包內建立一個名為a1.py的模組,在裡面對a、b、c、d、e、f等變數進行定義。 a = 11 b = 22 c = 33 d = 44 e = 55 f = 66   接下來我們可以直接在a2.py

Python專案中如何優雅的import

Python專案中如何優雅的import 前言 之前有一篇關於Python編碼規範的隨筆, 但是寫的比較雜亂, 因為提到了import語句, 在篇文章中, 我專門來講Python專案中如何更好的import 標準庫與第三方庫的匯入 匯入一個模組, 如果模組名太長, 則使用import

Jenkins構建Python專案提示:'python' 不是內部或外部命令,也不是可執行的程式

問題描述: jenkin整合python專案,立即構建後,發現未執行成功,檢視Console Output 提示:'Python' 不是內部或外部命令,也不是可執行的程式,如下圖: 1.在 Windows 提示符下執行是沒有問題。 2.把Jenkins專案配置中 python main.p

python基礎 —— 模組

collections namedtuple(‘名稱’, [屬性list]) 用來建立一個自定義的tuple物件(可以表示不變集合),規定了tuple元素的個數,並可以用屬性而不是索引來引用tuple的某個元素。 Point = namedtuple('Point', ['x',