如果你做過有多個文件的Python項目禀梳,那么你一定用過import語句杜窄。
即使是對于有多個項目的Python支持者來說,import也會讓人困惑算途!你可能正閱讀本文塞耕,因為希望更深入地了解Python中的導(dǎo)入,尤其是絕對和相對導(dǎo)入嘴瓤。
在本教程中筛谚,你將了解兩者之間的差異,以及它們的利弊蝎毡。我們立即開始吧!私信小編【PDF】可獲取python電子書一套
關(guān)于Import的快速回顧
你需要對Python模塊和包有一個很好的理解扎谎,以了解導(dǎo)入的工作方式逊移。Python模塊是一個擴展名是.py的文件拐叉,Python包是其中包含模塊的任何文件夾(或者,在Python 2中蔬芥,是至少包含一個init.py文件的文件夾)。
當一個模塊中的代碼需要訪問另一個模塊或包中的代碼時思喊,會發(fā)生什么情況岳服?導(dǎo)入它纲辽!
Import如何工作
但import究竟是如何工作的呢这吻?假設(shè)你導(dǎo)入一個模塊abc怠硼,就像這樣:
Python要做的第一件事是查找sys.modules中的abc名稱阀坏。這是預(yù)先導(dǎo)入的所有模塊的緩存酗洒。
如果在模塊緩存中沒有找到該名稱棋嘲,Python將通過內(nèi)置模塊列表進行搜索侄榴。這些模塊是和Python一起預(yù)先安裝的,并且可以在Python標準庫中找到在辆。如果在內(nèi)置模塊中仍沒有找到該名稱寇窑,那么Python在sys.path定義的目錄列表中搜索它窗市。此列表通常包括當前目錄福青,首先搜索該目錄媒役。
當Python找到該模塊時交惯,將它綁定到本地作用域中的名稱拳昌。這意味著現(xiàn)在定義了abc,而且可以在當前文件中使用,而不引發(fā)NameError。
如果找不到該名字,會得到ModuleNotFoundError醒颖。你可以在Python文檔找到更多關(guān)于導(dǎo)入的信息!
注意:安全問題
請注意,Python的導(dǎo)入系統(tǒng)會帶來一些重大的安全風(fēng)險。這主要是由于其靈活性。例如,模塊緩存是可寫的,并且有可能使用導(dǎo)入系統(tǒng)重寫Python核心功能。從第三方軟件包導(dǎo)入也可能給應(yīng)用程序帶來安全威脅。
導(dǎo)入語句語法
既然你知道導(dǎo)入語句是如何工作的齐莲,讓我們來探究它們的語法。你可以導(dǎo)入包和模塊。(注意,導(dǎo)入一個包基本上是導(dǎo)入包的init.py文件作為模塊。)還可以從包或模塊中導(dǎo)入特定的對象果覆。
一般有兩種類型的導(dǎo)入語法汞幢。當使用第一種時营罢,直接導(dǎo)入資源,如下所示:
abc可以是一個包或一個模塊躺坟。
當使用第二種語法時美侦,從另一個包或模塊導(dǎo)入資源具壮。下面是一個例子:
xyz可以是模塊心例、子包或?qū)ο罅锔珙惢蚝瘮?shù)匪补。你還可以重命名導(dǎo)入的資源喳逛,如:
這在腳本內(nèi)將導(dǎo)入的資源abc重命名為other_name窟坐。它現(xiàn)在必須被引用為other_name盔憨,否則它將不被識別萍摊。
導(dǎo)入語句的風(fēng)格
Python的官方風(fēng)格指南——PEP 8踊沸,在編寫導(dǎo)入語句時有幾個忠告。總結(jié)如下:
1. 導(dǎo)入總是位于文件的頂部檀何,在任何模塊注釋和文檔字符串之后。
2. 導(dǎo)入應(yīng)該根據(jù)導(dǎo)入情況來劃分廷支。通常有三類:
標準庫導(dǎo)入(Python的內(nèi)置模塊)
相關(guān)第三方導(dǎo)入(已安裝且不屬于當前應(yīng)用程序的模塊)
本地應(yīng)用程序?qū)耄▽儆诋斍皯?yīng)用程序的模塊)
3. 每一組導(dǎo)入應(yīng)該被空行隔開频鉴。
在每個導(dǎo)入組中按字母順序排列導(dǎo)入也是一個好主意。這使得查找特定的導(dǎo)入更加容易恋拍,尤其是當文件中有許多導(dǎo)入時垛孔。
下面是如何設(shè)計導(dǎo)入語句的示例:
上面的導(dǎo)入語句被劃分為三個不同的組,由空行分隔僵娃。它們也按字母順序排列在每組中概作。
絕對導(dǎo)入
你已經(jīng)掌握了如何編寫import語句以及如何像專業(yè)人士那樣設(shè)置樣式。現(xiàn)在是時候了解更多關(guān)于絕對導(dǎo)入的信息了默怨。絕對導(dǎo)入從項目根文件夾中使用其完整路徑導(dǎo)入指定的資源讯榕。
語法與實例
假設(shè)你有以下目錄結(jié)構(gòu):
有一個project目錄谆甜,包含兩個子目錄,package1和package2集绰。package1目錄有兩個文件规辱,module1.py和module2.py。
package2目錄有三個文件:兩個模塊:module3.py和module4.py栽燕,以及初始化文件init.py罕袋。它還包含一個目錄subpackage1,subpackage1又包含一個文件module5.py碍岔。
假設(shè)如下:
1.package1/module2.py包含一個函數(shù)function1浴讯。
2.package2/init.py包含一個類class1.
3.package2/subpackage1/module5.py包含一個函數(shù)function2.
以下是絕對導(dǎo)入的實際例子:
請注意,必須從頂級包文件夾中為每個包或文件提供詳細路徑捏肢。這有點類似于它的文件路徑,但是我們使用點(.)代替斜杠(/)鸵赫。
絕對導(dǎo)入的利弊
絕對導(dǎo)入是首選衣屏,因為它們非常明確和直接。僅僅通過查看語句就可以很容易地確定導(dǎo)入資源的位置辩棒。此外狼忱,即使導(dǎo)入語句的當前位置發(fā)生更改,絕對導(dǎo)入仍然有效一睁。事實上钻弄,PEP 8明確建議絕對導(dǎo)入。
然而者吁,有時窘俺,絕對導(dǎo)入會變得相當冗長,這取決于目錄結(jié)構(gòu)的復(fù)雜性砚偶。想象一下有這樣的語句:from package1.subpackage2.subpackage3.subpackage4.module5 import function6 那太荒謬了批销,對吧?幸運的是染坯,在這種情況下均芽,相對導(dǎo)入是一個很好的選擇!
相對導(dǎo)入
相對導(dǎo)入指定資源相對于當前位置導(dǎo)入单鹿,即導(dǎo)入語句所在的位置掀宋。相對導(dǎo)入有兩種類型:隱式和顯式。隱式相對導(dǎo)入在Python 3中已經(jīng)被棄用,所以我不會在這里涉及它們劲妙。
語法與實例
相對導(dǎo)入的語法取決于當前位置以及要導(dǎo)入的模塊湃鹊、包或?qū)ο蟮奈恢谩O旅媸且恍┫鄬?dǎo)入的例子:
你可以看到上面每個導(dǎo)入語句中至少有一個點侨颈。相對導(dǎo)入使用點標記來指定位置余赢。
一個點意味著引用的模塊或包位于與當前位置相同的目錄中。兩個點意味著它在當前位置的父目錄中哈垢,也就是上層的目錄妻柒。三個點意味著它在祖父母目錄中,等等耘分。如果你使用類似UNIX的操作系統(tǒng)举塔,可能對此很熟悉!
假設(shè)你擁有與以前相同的目錄結(jié)構(gòu):
回憶文件內(nèi)容:
1.package1/module2.py包含一個函數(shù)function1拜秧。
2.package2/init.py包含一個類class1.
3.package2/subpackage1/module5.py包含一個函數(shù)function2.
你可以通過這種方式將function1導(dǎo)入package1/module1.py中:
這里只使用一個點,因為module2.py位于與當前模塊相同的目錄中暖庄,當前模塊是module1.py聊替。
你可以將class1 和function2 以這種方式導(dǎo)入package2/module3.py文件中:
在第一個導(dǎo)入語句中,一個點表示你正在從當前包導(dǎo)入class1肩钠。別忘了泣港,導(dǎo)入一個包基本上是導(dǎo)入包的init.py文件作為模塊。在第二個導(dǎo)入語句中价匠,你將再次使用一個點当纱,因為subpackage1 與當前模塊module3.py位于同一個目錄中。
相對導(dǎo)入的利弊
相對導(dǎo)入的一個明顯優(yōu)勢是它們相當簡練踩窖。根據(jù)當前位置坡氯,它們可以將你之前看到的冗長的可笑的導(dǎo)入語句轉(zhuǎn)換為如下簡單的語句:
不幸的是手形,相對導(dǎo)入可能是混亂的,特別是對于目錄結(jié)構(gòu)可能改變的共享項目悯恍。相對導(dǎo)入也不像絕對導(dǎo)入一樣可讀库糠,而且很難識別導(dǎo)入資源的位置。
結(jié)尾
來到絕對和相對導(dǎo)入速成課程的結(jié)尾涮毫,很好曼玩!現(xiàn)在,你熟悉了導(dǎo)入的工作原理窒百。你已經(jīng)學(xué)習(xí)了編寫導(dǎo)入語句的最佳實踐黍判,并且你知道絕對導(dǎo)入和相對導(dǎo)入之間的區(qū)別。
有了新的技能篙梢,你可以自信地從Python標準庫顷帖、第三方包和自己的本地包導(dǎo)入包和模塊。記住渤滞,你通常應(yīng)該選擇絕對導(dǎo)入贬墩,而不是相對導(dǎo)入,除非路徑是復(fù)雜的妄呕,并且會使聲明太長陶舞。