Python中創(chuàng)建包和增添包的路徑(sys.path.append())
python中創(chuàng)建自己的包(package),其實(shí)就只需要里創(chuàng)建一個(gè)文件夾就可以了。文件夾里不是必須要有是__init__.py這個(gè)文件的,不過如果你的文件夾里存在這個(gè)__init__.py文件,那么當(dāng)你在import這個(gè)包時(shí)python會(huì)立刻執(zhí)行__init__.py里的內(nèi)容并且只會(huì)執(zhí)行__init__.py。相反,如果你的文件夾(這個(gè)package)里沒有這個(gè)文件,當(dāng)import這個(gè)package時(shí)就不會(huì)做任何事情(換句話說你python只會(huì)load這個(gè)包的名稱,但里面接著進(jìn)行任何其他的操作,你可以查看這個(gè)包的默認(rèn)屬性)。因此一般情況下,一個(gè)package中是必須要有__init__.py
,并且常常會(huì)在__init__.py
文件中執(zhí)行import語句,比如import進(jìn)一些本文件夾里的一些包,或者封裝好一些類,一些函數(shù)。這樣做的好處是,只要你import了這個(gè)package,那么你就可以使用__init__.py
中l(wèi)oad的所有包。
1、創(chuàng)造一個(gè)包
我們要做的就是兩件事
在工作目錄下創(chuàng)建一個(gè)文件夾命名為
My_package
在文件夾
My_package
中再創(chuàng)建一個(gè)__init__.py
文件
__init__.py
:
print('包加載成功')
我們可以是在My_package文件夾的同一級目錄中加載import一下(注意工作目錄要在的同一級目錄中才能加載到My_package,后面會(huì)介紹如果不在同一級目錄該怎么做)
import My_package #輸出 包加載成功
可以看到加載包的時(shí)候(并且在My_package目錄下自動(dòng)生成了一個(gè)__pycache__
的文件夾),我們寫在__init__.py
中的命令行被執(zhí)行了接下來我們更加豐富一下__init__.py
的內(nèi)容,給這個(gè)里面添加兩個(gè)函數(shù):
__init__.py
:
print('包加載成功') def fun1(a): print('執(zhí)行函數(shù)1:',a) return def fun2(a): print('執(zhí)行函數(shù)2:',a)
接下來我們導(dǎo)入這個(gè)包,并執(zhí)行里面的函數(shù)。
import My_package My_package.fun1('開始執(zhí)行') My_package.fun2('開始執(zhí)行') #輸出 包加載成功 執(zhí)行函數(shù)1: 開始執(zhí)行 執(zhí)行函數(shù)2: 開始執(zhí)行
可以看到這些函數(shù)都已經(jīng)被執(zhí)行了。
當(dāng)然我們可以使用from My_package import *
這種方式來完成上面的內(nèi)容
from My_package import * fun1('開始執(zhí)行') fun2('開始執(zhí)行') #輸出 包加載成功 執(zhí)行函數(shù)1: 開始執(zhí)行 執(zhí)行函數(shù)2: 開始執(zhí)行
可以看到結(jié)果是一樣的,由此我們已經(jīng)創(chuàng)建自己的包了
2、為包增加模塊
我們常見的包里面都會(huì)有很多很多其他的.py程序,并不是只有__init__.py
,因?yàn)橛行﹥?nèi)容不需要在導(dǎo)入的時(shí)候就執(zhí)行。下面我們?yōu)镸y_package增加兩個(gè)模塊。model1.py和model2.py。
model1.py
print('這里是model1') def fun1(): print('這里是model1的第一個(gè)函數(shù)') return def fun2(): print('這里是model1的第二個(gè)函數(shù)') return
model2.py
print('這里是model2') def fun1(): print('這里是model2的第一個(gè)函數(shù)') return def fun2(): print('這里是model2的第二個(gè)函數(shù)') return
創(chuàng)建完這兩個(gè)模塊之后,我們My_package文件夾下就有四個(gè)文件了:
- 文件夾
__pycache__
- 文件
__init__.py
- 文件model1.py
- 文件model2.py
下面我們用不同的方式來導(dǎo)入包和模塊,并執(zhí)行。
方式一:import My_package
.模塊名
import My_package.model1 import My_package.model2 #輸出 包加載成功 這里是model1 這里是model2 My_package.model1.fun1() My_package.model2.fun2() #輸出 這里是model1的第一個(gè)函數(shù) 這里是model2的第二個(gè)函數(shù) My_package.fun1('OK') #輸出 執(zhí)行函數(shù)1: OK
可以看到__init__.py
依然被執(zhí)行了的,而且在導(dǎo)入包的時(shí)候,不同的model中的代碼也在import的時(shí)候執(zhí)行了。需要注意的是,采用這種import 包名.模塊名的方式,會(huì)出現(xiàn)一個(gè)全局變量My_package來指向這個(gè)包(我們可以通過dir(My_package)來查看這個(gè)全局變量的屬性,我們可以看到’fun1’,‘fun2’,‘model1’,'model2’都出現(xiàn)了),因此我們可以采用 包名.模塊名.函數(shù)名 的方式調(diào)用不同model的函數(shù)。
我們還可以通過My_package.函數(shù)名的方式來執(zhí)行__init__.py
里的函數(shù)(這是因?yàn)椴捎胕mport 包名.模塊名的方式來載入,python依然會(huì)執(zhí)行package中的__init__.py
,并且生成的對象會(huì)被命名為My_package)。
我們可以通過加as的方法來對這一串很長的包名來重新命名,這就是介紹的第二種方法。
方式二:import My_package.model1 as xxx
import My_package.model1 as new_name1 import My_package.model2 as new_name2 #輸出 包加載成功 這里是model1 這里是model2 new_name1.fun1() new_name2.fun2() #輸出 這里是model1的第一個(gè)函數(shù) 這里是model2的第二個(gè)函數(shù)
可以看到我們可以使用new_name1這個(gè)變量來代替My_package.model1。這種采用as進(jìn)行重命名的方式需要注意的是,此時(shí)python中將不會(huì)出現(xiàn)叫My_package的全局變量來指向這個(gè)package了,因此程序會(huì)無法找到My_package這個(gè)變量。因?yàn)閜ython會(huì)將最外層的這個(gè)model1賦值給new_name1
,而不再保存My_package的任何東西,盡管執(zhí)行了My_package
中__init__.py
。
方法三:from My_package import model1
from My_package import model1 from My_package import model2 #輸出 包加載成功 這里是model1 這里是model2 model1.fun1() model2.fun2() #輸出 這里是model1的第一個(gè)函數(shù) 這里是model2的第二個(gè)函數(shù) My_package.fun1('OK') #輸出 NameError: name 'My_package' is not defined --------------------------------------------------------------------------- NameError Traceback (most recent call last) /tmp/ipykernel_9767/1183774725.py in <module> 2 from My_package import model2 3 ----> 4 My_package.fun1('OK') NameError: name 'My_package' is not defined
根據(jù)導(dǎo)入包的方式顧名思義,“從My_package中導(dǎo)入model1.py”,這個(gè)時(shí)候我們可以直接使用model1.函數(shù)名()來調(diào)用函數(shù)了??梢钥吹礁耙环N方式一樣此時(shí)python中將不會(huì)出現(xiàn)叫My_package的全局變量,雖然已經(jīng)執(zhí)行了__init__.py
,但python沒有將My_package賦值給任何變量,因此無法找到My_package
。
方法四:from My_package import *
from My_package import * fun1('OK') #輸出 包加載成功 執(zhí)行函數(shù)1: OK modle1.fun1() #輸出 NameError: name 'modle1' is not defined
這種方式加載其實(shí)就相當(dāng)于直接把__init__.py
直接加載到工作區(qū),直接可以使用__init__.py
中的類或者函數(shù),不用再添加My_package.函數(shù)名。不過要注意的是這種導(dǎo)入,只導(dǎo)入了My_package中__init__.py
,并沒有導(dǎo)入其他的model1,或者model2,因此第三行是會(huì)報(bào)錯(cuò)的(并且我們可以看到并沒有任何model的打印出現(xiàn),其實(shí)這也側(cè)面說明了當(dāng)只采用import package的方式導(dǎo)入包時(shí),python只會(huì)執(zhí)行__init__.py
)。
我們又該怎么調(diào)用model里的函數(shù)呢?用下面的方式就可以了。
from My_package.model1 import * #輸出 包加載成功 這里是model1 fun1() fun2() #輸出 這里是model1的第一個(gè)函數(shù) 這里是model1的第二個(gè)函數(shù)
其實(shí)不推薦大家采用這這種方法,因?yàn)槿绻诓煌琺odel中出現(xiàn)了相同的函數(shù)名方法,后導(dǎo)入的包將會(huì)把前者的函數(shù)名給掩蓋。比如本文的這兩個(gè)例子,model1和modle2的函數(shù)都叫做fun1,fun2,那如果我們按照這個(gè)方式同時(shí)導(dǎo)入這兩個(gè)模塊,會(huì)出現(xiàn)什么問題呢?
from My_package.model1 import * from My_package.model2 import * #輸出 包加載成功 這里是model1 這里是model2 fun1() fun2() #輸出 這里是model2的第一個(gè)函數(shù) 這里是model2的第二個(gè)函數(shù)
大家可以看到前兩句執(zhí)行之后,顯示兩個(gè)包都被導(dǎo)入了,但是我們執(zhí)行fun1和fun2時(shí)編譯器識別的是后導(dǎo)入的模塊model2的fun1和fun2,而model2的函數(shù)被掩蓋了,因此不推薦大家采用方法4作為導(dǎo)入包的方法。
3、包的路徑問題
剛學(xué)python的時(shí)候我非常好奇,import的包到底在那里?我pip install xxx下載下來的包又在那里?(當(dāng)然可以通過路徑查找),為什么下載下來的包在不同的地方但是import卻能找到這些散落到各地的包?其實(shí)這些問題都?xì)w結(jié)到import是如何導(dǎo)入到包的。其實(shí)import包的時(shí)候時(shí),python會(huì)在一些路徑中搜索是否存在名字相符的文件夾(package)或者.py文件。
大家可以通過運(yùn)行:
import sys sys.path #輸出 ['/home/g4/.vscode/extensions/ms-toolsai.jupyter-2021.3.684299474/pythonFiles/vscode_datascience_helpers/../.does-not-exist', '/home/g4/.vscode/extensions/ms-toolsai.jupyter-2021.3.684299474/pythonFiles', '/home/g4/.vscode/extensions/ms-toolsai.jupyter-2021.3.684299474/pythonFiles/lib/python',...] (在ubuntu系統(tǒng)上演示的)
查看的當(dāng)前的系統(tǒng)環(huán)境環(huán)境變量(sys.path是一個(gè)列表,每個(gè)元素是路徑),在import的時(shí)候python就會(huì)在這些路徑中去尋找有沒有符合的名字,如果沒有找到,就會(huì)返回我們最常見的"ModuleNotFoundError: No module named ‘kae’".
通過這個(gè)問題的討論其實(shí)我們可以知道,如果我們自己編寫的包想要被import到,就需要把包的路徑寫道環(huán)境變量中(前文演示的時(shí)候工作目錄是會(huì)自動(dòng)加入到import的查詢范圍內(nèi)的)。我們不用去修改電腦的環(huán)境變量,因?yàn)閯傉f道sys.path是一個(gè)列表,因此我們可以通過append方法加入我們包所在路徑可以了。
為了演示,我把前面寫好的My_package文件夾放到了工作目錄的下一級目錄。
import My_package #輸出 ModuleNotFoundError: No module named 'My_pacackge' --------------------------------------------------------------------------- ModuleNotFoundError Traceback (most recent call last) /tmp/ipykernel_31481/1446587236.py in <module> ----> 1 import My_pacackge ModuleNotFoundError: No module named 'My_pacackge'
不出意外的,報(bào)錯(cuò)了。接下來我們添加My_package文件夾的目錄到系統(tǒng)目錄中
import sys sys.path.append('/home/g4/桌面/project') print('##############') import My_package #輸出 ############## 包加載成功
可以看到,包被正常加載了。對于自己寫的模塊我們可以采用這種方式來對其進(jìn)行加載。
4、相對路徑導(dǎo)入包的問題
為了更好區(qū)分,我們將model2.py中的兩個(gè)函數(shù)改一下名字。
#學(xué)習(xí)中遇到問題沒人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流群:531509025 print('這里是model2') def model2_fun1(): print('這里是model2的第一個(gè)函數(shù)') return def model2_fun1fun2(): print('這里是model2的第二個(gè)函數(shù)') return
在同一個(gè)package中,如果model1.py中想使用model2.py的函數(shù),那我們可以通過import My_package.model2的方式進(jìn)行正常導(dǎo)入。不過會(huì)有個(gè)問題,如果某一天,我把文件夾My_package更名了,那么此時(shí)mode1.py中的import My_package.model2將會(huì)報(bào)錯(cuò)。如何避免這個(gè)問題呢,我們就可以采用相對路徑的方式導(dǎo)入包。即將import My_package.model2改為import .model2的方式導(dǎo)入。
那么無論文件夾My_package如何更名,只要model1.py與model2.py是在同一個(gè)package下的,那么這行代碼都會(huì)正確找到。
接下來我們要說一下原理:python相對路徑導(dǎo)入包的方法其本質(zhì)是,都是先找到絕對路徑再import。他會(huì)根據(jù)model1的__package__
變量去找到model1的package是誰(本例中就是My_package),再將import .model2復(fù)原成import My_package.model2,從而完成導(dǎo)入。
明白這個(gè)原理之后,相信大家就會(huì)知道,為什么我直接運(yùn)行model1.py時(shí),其中的import .model2會(huì)報(bào)錯(cuò)了。因?yàn)楫?dāng)你直接運(yùn)行model1.py的時(shí)候,這個(gè)文件將會(huì)當(dāng)作main package 加載到內(nèi)存中,此時(shí)它并不屬于任何的的package,所以import .model2就不會(huì)轉(zhuǎn)化成import My_package.model2,也就無法找到正確的model2,從而報(bào)錯(cuò)。
到此這篇關(guān)于Python中創(chuàng)建包和增添包的路徑(sys.path.append())的文章就介紹到這了,更多相關(guān)Python創(chuàng)建包和增添包路徑內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python計(jì)數(shù)器collections.Counter用法詳解
本文主要介紹了Python計(jì)數(shù)器collections.Counter用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03Pandas數(shù)據(jù)分析固定時(shí)間點(diǎn)和時(shí)間差
這篇文章主要介紹了Pandas數(shù)據(jù)分析固定時(shí)間點(diǎn)和時(shí)間差,文章未日澳主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08超詳細(xì)OpenMV與STM32單片機(jī)通信 附完整源碼
這篇文章主要介紹了OpenMV與STM32單片機(jī)通信的相關(guān)知識,在文章結(jié)尾給大家提供了項(xiàng)目源碼,需要的朋友可以參考下2021-11-11Python爬取當(dāng)網(wǎng)書籍?dāng)?shù)據(jù)并數(shù)據(jù)可視化展示
這篇文章主要介紹了Python爬取當(dāng)網(wǎng)書籍?dāng)?shù)據(jù)并數(shù)據(jù)可視化展示,下面文章圍繞Python爬蟲的相關(guān)資料展開對爬取當(dāng)網(wǎng)書籍?dāng)?shù)據(jù)的詳細(xì)介紹,需要的小伙伴可以參考一下,希望對你有所幫助2022-01-01python 利用for循環(huán) 保存多個(gè)圖像或者文件的實(shí)例
今天小編就為大家分享一篇python 利用for循環(huán) 保存多個(gè)圖像或者文件的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-11-11