溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Python模塊導(dǎo)入機(jī)制與大型項(xiàng)目的規(guī)范是什么

發(fā)布時(shí)間:2020-10-12 14:38:35 來(lái)源:億速云 閱讀:188 作者:小新 欄目:編程語(yǔ)言

這篇文章主要介紹Python模塊導(dǎo)入機(jī)制與大型項(xiàng)目的規(guī)范是什么,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

Python模塊導(dǎo)入

日常編程中,為了能夠復(fù)用寫(xiě)過(guò)的代碼邏輯,我們都會(huì)把這些代碼封裝成為模塊,需要用到的時(shí)候可以直接導(dǎo)入復(fù)用,以便提高我們的開(kāi)發(fā)效率。 module能定義函數(shù)、類(lèi)、變量,也能包含可執(zhí)行的代碼。module來(lái)源有3種: ①Python內(nèi)置的模塊(標(biāo)準(zhǔn)庫(kù)); ②第三方模塊; ③自定義模塊;

導(dǎo)入原理

模塊的導(dǎo)入一般是在文件頭使用import關(guān)鍵字,import一個(gè)模塊相當(dāng)于先執(zhí)行了一次這個(gè)被導(dǎo)入模塊,然后在本命名空間建立一個(gè)與被導(dǎo)入模塊命名空間的聯(lián)系,相當(dāng)于在本命名空間新建了一個(gè)變量,這個(gè)變量名稱(chēng)是被導(dǎo)入模塊的名稱(chēng),指向被導(dǎo)入模塊的命名空間。所以導(dǎo)入的這個(gè)模塊相當(dāng)于一個(gè)變量,因此多次導(dǎo)入同一個(gè)模塊只有第一次導(dǎo)入的時(shí)候會(huì)被執(zhí)行(后續(xù)導(dǎo)入會(huì)判斷到這個(gè)模塊變量已存在所以不執(zhí)行)

Python模塊導(dǎo)入機(jī)制與大型項(xiàng)目的規(guī)范是什么

路徑查找機(jī)制

每一個(gè)導(dǎo)入的模塊都會(huì)在Python內(nèi)置字典sys.modules中,Python一啟動(dòng),它將被加載在內(nèi)存中,當(dāng)我們導(dǎo)入新modules,sys.modules將自動(dòng)記錄下該module。 Python的模塊查找路徑的機(jī)制是:

  1. 查找sys.path中的所有路徑下是否有該模塊,有則開(kāi)辟新空間加載該模塊;
  2. 查看sys.modules中是否有內(nèi)置包或已安裝的第三方包,有則開(kāi)辟新空間加載該模塊;

所以對(duì)于我們自己編寫(xiě)的模塊,如果封裝并發(fā)布到了PyPi,則可以用pip install直接安裝,并在啟動(dòng)時(shí)加載在內(nèi)存中,通過(guò)sys.modules可以查看到 而對(duì)于僅需要在本項(xiàng)目中復(fù)用的模塊,我們?cè)趶?fù)用代碼中將其路徑加入到sys.path中,同樣可以引用到該模塊。

絕對(duì)路徑導(dǎo)入

所有的模塊import都從“根節(jié)點(diǎn)”開(kāi)始。根節(jié)點(diǎn)的位置由sys.path中的路徑?jīng)Q定,項(xiàng)目的根目錄一般自動(dòng)在sys.path中。如果希望程序能處處執(zhí)行,需手動(dòng)修改sys.path

import sys,os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))#項(xiàng)目根目錄所在的絕對(duì)路徑sys.path.append(BASE_DIR)import A, B #導(dǎo)入A、B包復(fù)制代碼

相對(duì)路徑導(dǎo)入

只關(guān)心相對(duì)自己當(dāng)前目錄的模塊位置就好。不能在包(package)的內(nèi)部直接執(zhí)行(會(huì)報(bào)錯(cuò))。不管根節(jié)點(diǎn)在哪兒,包內(nèi)的模塊相對(duì)位置都是正確的。

#from . import b2 #這種導(dǎo)入方式會(huì)報(bào)錯(cuò),只有在包內(nèi)部直接執(zhí)行的時(shí)候才可以這樣導(dǎo)入。import b2#正確b2.print_b2()復(fù)制代碼

Python模塊導(dǎo)入常見(jiàn)問(wèn)題

  • 單獨(dú)import某個(gè)包名稱(chēng)時(shí),不會(huì)導(dǎo)入該包中所包含的所有子模塊 解決辦法:導(dǎo)入的包中也包含了其他包的導(dǎo)入,此時(shí)需要在每個(gè)包的init.py文件中導(dǎo)入該包下的所有模塊,最上層才可以直接引用最下層的包的類(lèi)和方法

init文件

當(dāng)一個(gè)文件夾下有init.py時(shí),意為該文件夾是一個(gè)包(package),其下的多個(gè)模塊(module)構(gòu)成一個(gè)整體,而這些模塊(module)都可通過(guò)同一個(gè)包(package)導(dǎo)入其他代碼中。 其中init.py文件 用于組織包(package),方便管理各個(gè)模塊之間的引用、控制著包的導(dǎo)入行為。

該文件可以什么內(nèi)容都不寫(xiě),即為空文件(為空時(shí),僅僅用import [該包]形式 是什么也做不了的),存在即可,相當(dāng)于一個(gè)標(biāo)記。

在python3中,即使包下沒(méi)有init.py文件,import 包仍然不會(huì)報(bào)錯(cuò),而在python2中,包下一定要有該文件,否則import 包會(huì)報(bào)錯(cuò)

all變量

all 是一個(gè)重要的變量,用來(lái)指定此包(package)被import *時(shí),哪些模塊(module)會(huì)被import進(jìn)【當(dāng)前作用域中】。不在all列表中的模塊不會(huì)被其他程序引用??梢灾貙?xiě)all,如 all= [‘當(dāng)前所屬包模塊1名字’, ‘模塊1名字’],如果寫(xiě)了這個(gè),則會(huì)按列表中的模塊名進(jìn)行導(dǎo)入

name變量

在包內(nèi)部直接運(yùn)行時(shí),包的name == 'main',但是在外部導(dǎo)入包是,可以通過(guò)

if __name__ == '__main__':復(fù)制代碼

來(lái)避免實(shí)現(xiàn)包內(nèi)部調(diào)試時(shí)的邏輯

循環(huán)導(dǎo)入

當(dāng)兩個(gè)模塊A和B之間相互import時(shí),就會(huì)出現(xiàn)循環(huán)導(dǎo)入的問(wèn)題,此時(shí)程序運(yùn)行會(huì)報(bào)錯(cuò):can not import name xxx,如:

# a.pyprint('from a.py')from b import x

y = 'a'復(fù)制代碼
# b.pyprint('from b.py')from a import y

x = 'b'復(fù)制代碼

我們來(lái)分析一下這種錯(cuò)誤是怎么出現(xiàn)的:

  1. 在sys.modules中查找 符號(hào)“module b”;
  2. 如果符號(hào)“module b”存在,則獲得符號(hào)“module b”對(duì)應(yīng)的module對(duì)象; 從的dict中獲得 符號(hào)“x”對(duì)應(yīng)的對(duì)象。如果“x”不存在,則拋出異?!癐mportError: cannot import name ‘x’”
  3. 如果符號(hào)“module b”不存在,則創(chuàng)建一個(gè)新的 module對(duì)象。不過(guò)此時(shí)該新module對(duì)象的dict為空。然后執(zhí)行module b.py文件中的語(yǔ)句,填充的dict。

因此在a.py中執(zhí)行from b import x的順序就是1->3,先引入b,b里面from a import y由相當(dāng)于執(zhí)行了a.py,順序是1->2,因?yàn)榇藭r(shí)b已經(jīng)引入所以不會(huì)執(zhí)行3,2中無(wú)法找到x對(duì)象,因?yàn)橐隻時(shí)還沒(méi)執(zhí)行到x='b'這一步,所以報(bào)錯(cuò)了

解決辦法

  1. 延遲導(dǎo)入,把import語(yǔ)句寫(xiě)在方法/函數(shù)里,將它的作用域限制在局部;
  2. 頂層先引入模塊,再把from x import y改成import x.y形式;
  3. 其實(shí)出現(xiàn)循環(huán)引用問(wèn)題的根本原因是程序設(shè)計(jì)不合理,每個(gè)包都應(yīng)該由上層使用的模塊去導(dǎo)入,而不應(yīng)該在包與包之間各種相互導(dǎo)入,所以應(yīng)該更改代碼布局,可合并或分離競(jìng)爭(zhēng)資源;

大型項(xiàng)目中Python模塊導(dǎo)入規(guī)范

分離模塊,將同一類(lèi)別的模塊放在同一目錄下,形成類(lèi)別分明的目錄架構(gòu),如:

Python模塊導(dǎo)入機(jī)制與大型項(xiàng)目的規(guī)范是什么

  1. 每一個(gè)模塊目錄都要寫(xiě)init.py文件,可以同時(shí)定義all限定可導(dǎo)入的范圍;
  2. 源碼根目錄可以定義BASE_DIR,限定好根目錄路徑,啟動(dòng)py文件可以用絕對(duì)路徑導(dǎo)入各個(gè)模塊,將必要模塊都加入到sys.path中;
  3. 各個(gè)服務(wù)之間(例如model需要引入common的模塊方法),可以通過(guò)相對(duì)路徑引用模塊;
  4. 程序設(shè)計(jì)時(shí)避免循環(huán)導(dǎo)入,可由調(diào)用者(服務(wù)文件)作為上層第三方引入需要的各個(gè)模塊,這樣就可以減少各個(gè)模塊的相互導(dǎo)入。

以上是Python模塊導(dǎo)入機(jī)制與大型項(xiàng)目的規(guī)范是什么的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI