## 如何認(rèn)識(shí)python中的包和模塊
//**//作為一個(gè)python小菜鳥,剛接觸python并沒(méi)有多久禁炒,也只是將將掌握python的基本用法负芋,在一個(gè)大佬的脅迫下才會(huì)想著發(fā)表一些覺(jué)得有用的東西,也都屬于個(gè)人見(jiàn)解带猴,其中有可能還會(huì)有很多認(rèn)識(shí)上的錯(cuò)誤吼畏,希望各路大佬若是很不幸看到的話督赤,幫助一下糾正錯(cuò)誤嘁灯,要是大佬們有什么好的建議能夠提出泻蚊,在下感激不盡,若是有幸剛好幫您得到一些新體會(huì)的話丑婿,這篇文章也就實(shí)現(xiàn)了它的價(jià)值性雄,那我們就從這開(kāi)始吧:**
**1.如何理解包和模塊的概念**
? ? ? 首先,在日常的開(kāi)發(fā)之中羹奉,我們經(jīng)常會(huì)遇到對(duì)代碼的重用秒旋,維護(hù)以及擴(kuò)展等問(wèn)題,當(dāng)我們?cè)谛薷拇a的時(shí)候诀拭,無(wú)疑代碼的耦合是一個(gè)大問(wèn)題迁筛,所謂耦合,就是代碼塊之間的相互關(guān)系耕挨,本身python最小的運(yùn)作單元就是一個(gè)代碼塊细卧,也可以解釋為一條完整語(yǔ)句,作為解釋型語(yǔ)言筒占,當(dāng)然要將懶(其實(shí)也可以解釋為方便贪庙,都一樣)發(fā)揮到極致,功能寫出來(lái)之后像我肯定是不會(huì)再想著下次開(kāi)始再重頭寫翰苫,好比也許我當(dāng)時(shí)處于一個(gè)非常極端的狀態(tài)止邮,比如剛跟女朋友分手之類的,心情極度悲憤的情況下定義出的方法和變量估計(jì)日后的我想看看是什么都有一定難度奏窑,那么這時(shí)候导披,如果再有可能當(dāng)時(shí)在純用面對(duì)過(guò)程的思想隨手寫的一個(gè)功能,后邊的代碼重用無(wú)疑是個(gè)大問(wèn)題埃唯。
? ? ? 那么盛卡,如果說(shuō)不管什么時(shí)候我都想再次使用我自己的代碼,而且有一種敢為天下先的精神筑凫,獻(xiàn)出自己的代碼給別人使用滑沧,不過(guò)這時(shí)候問(wèn)題又來(lái)了并村,我自己有可能都忘了自己在和前任女朋友分開(kāi)時(shí)候是什么心情下定義的變量是什么意思,別人大概率也不咋會(huì)知道滓技,加上要是耦合度稍微有那么點(diǎn)高哩牍,一個(gè)復(fù)制粘貼也許都變了樣子,加上python每次錯(cuò)誤縮進(jìn)都有可能讓你有種吃了那啥的沖動(dòng)令漂,我覺(jué)得除了前端的人會(huì)很開(kāi)心直接粘貼復(fù)制省時(shí)間膝昆,我還沒(méi)見(jiàn)過(guò)python粘貼復(fù)制省時(shí)間的。
? ? ? 我們?cè)倩剡^(guò)頭來(lái)講下耦合的問(wèn)題叠必,在你勇敢地站了出來(lái)荚孵,將自己的身為程序員的才能發(fā)揮到了極致,所有的東西寫在了一個(gè)python文件中纬朝,五六千行代碼收叶,可以讓人眼花繚亂,然而可怕的是共苛,一旦某一點(diǎn)出錯(cuò)判没,又像是看到幾噸那啥一樣惡心,注意隅茎,你在后面五六千行代碼中還不知道寫了啥相關(guān)聯(lián)的東西澄峰,滿堂紅的光彩我要是在一邊笑估計(jì)會(huì)被你打死,耦合意思就是相互聯(lián)系辟犀,動(dòng)了一個(gè)功能代碼錯(cuò)的越多俏竞,耦合度越高,越說(shuō)明你邏輯嚴(yán)密堂竟,環(huán)環(huán)相扣魂毁,也有可能是粘貼復(fù)制太多,牽一發(fā)而動(dòng)全身跃捣。這時(shí)候我們就可以很開(kāi)心的提出一個(gè)叫做解耦和的概念漱牵,這個(gè)先聲明,解耦合是一種降低耦合度的舉動(dòng)并不是直接讓它們一點(diǎn)聯(lián)系沒(méi)有疚漆,沒(méi)有直接功能的代碼只是一個(gè)架子酣胀,好比網(wǎng)頁(yè)的交互,也許你只是做了一個(gè)樣式讓別人欣賞下你做網(wǎng)頁(yè)的水平娶聘,但是闻镶,花瓶并不是人人都喜歡的。
? ? ? 那么丸升,我們?cè)撊绾螖[脫自身邏輯的困擾呢铆农,如果我只是單純想做一個(gè)功能,然后各個(gè)我以后的程序里想要使用這個(gè)功能可以隨時(shí)拿過(guò)來(lái)用狡耻,這個(gè)時(shí)候我們就可以來(lái)了解下python中的模塊(modules)了墩剖。
? ? ? 既然代碼如果寫在一個(gè)文件中猴凹,那么會(huì)有很大的量讓我來(lái)思考和修改,那么我把它細(xì)分岭皂,相似的功能放在一個(gè)文件郊霎,比如類型,方法爷绘,變量等等书劝,使用一個(gè) “import” 的關(guān)鍵字來(lái)引入,是不是就可以很方便就看了土至,然后不管怎么用购对,我只要把它帶上,到時(shí)候修改的時(shí)候根據(jù)我自己的需求隨意修改陶因,這樣似乎也是一個(gè)很好的選擇骡苞,很開(kāi)心如果你接受了這樣的思想并且已經(jīng)知道了import的方式 ,那么這個(gè)modules的使用思想我覺(jué)得是沒(méi)什么問(wèn)題了坑赡。
? ? ? 那么既然模塊指的是一個(gè)python文件烙如,那么放這個(gè)東西的文件夾是什么呢么抗,不會(huì)是package(包)吧毅否,如果你是這么想,很好蝇刀,你已經(jīng)得到了一半的精髓螟加,我們?cè)谑褂胢odules的時(shí)候,除非在同一文件夾下吞琐,是不能直接引入的捆探,首先pycharm它也找不到,其次就是如果你把幾個(gè)模塊寫成了一樣的文件名站粟,恭喜你黍图,你自己也許都不知道引入的是哪一個(gè),再者說(shuō)奴烙,你也不能像我上面說(shuō)的用一次改一次助被,那個(gè)是比較特殊需求的時(shí)候,你把它復(fù)制出來(lái)改一下切诀,大部分時(shí)候揩环,功能需求應(yīng)該是普遍性相似的東西,所以為了再方便一點(diǎn) 幅虑,我們就有了package(包)這個(gè)好東西丰滑,簡(jiǎn)單來(lái)說(shuō),你的modules好比是一個(gè)個(gè)好用的工具倒庵,非特殊時(shí)候不用拿出來(lái)重新鍛造褒墨,而你的包就是一個(gè)工具箱炫刷,你可以把你的工具放在里面,做好區(qū)分之后郁妈,不管我需要用他們干什么只需要先找到這個(gè)包然后就可以拿出我的工具然后快樂(lè)自己柬唯,不管是維護(hù)還是擴(kuò)展要干什么直接在那個(gè)python文件里修改就好了反正也不會(huì)礙著其他功能什么事情就算在里面新加多少個(gè)module,好比在包里再放上幾塊磚圃庭,只要電腦受的了锄奢,反正我自己也不累,這個(gè)就是最完美的了剧腻。
? ? ? 不過(guò)拘央,還是那一個(gè)問(wèn)題,你說(shuō)這個(gè)文件夾我用來(lái)放的是需要我自己?jiǎn)为?dú)運(yùn)行的東西還有一些雜物只是拿出來(lái)看看你的包能不能用隨便練練手书在,而且跟我要用的東西有一些相似灰伟,名字上有些問(wèn)題,當(dāng)然區(qū)分方法我們一會(huì)會(huì)再提出來(lái)儒旬,那么標(biāo)準(zhǔn)的包和你的文件夾到底有什么區(qū)別栏账,它里面還有一個(gè)__init__.py的文件,里面裝的是__all__=[“栈源。挡爵。∩蹩眩”茶鹃,“。艰亮。闭翩。”迄埃,疗韵。。侄非。蕉汪。],不過(guò)這個(gè)里面只是你在使用這個(gè)包的時(shí)候直接可以使用的模塊彩库,大多時(shí)候吧肤无,這個(gè)文件是對(duì)包的最好分辨工具,其他文件夾沒(méi)有這個(gè)但是有你的python文件雖然說(shuō)也可以調(diào)用骇钦,但是書包和旅行包始終你會(huì)知道有什么不一樣的宛渐,你要是把書包當(dāng)作一個(gè)旅行包用我也沒(méi)辦法,也就看上去不太好看而已,在代碼上確實(shí)有點(diǎn)不太標(biāo)準(zhǔn)窥翩。
? **2.包和模塊的使用**
? ? ? 既然包和模塊已經(jīng)理解的差不多了业岁,那么我們現(xiàn)在可以來(lái)學(xué)習(xí)下它們的用法,那么我們就從以下的流程來(lái)看看它們是如何使用的:
`在這里插入代碼片`#### 1 包的定義
? ? ? 因?yàn)閯倓傄呀?jīng)講過(guò)包本質(zhì)就是個(gè)文件夾寇蚊,那么我可以設(shè)置一個(gè)demo01文件夾笔时,在其中設(shè)置一個(gè)文件夾modules,那么這個(gè)文件夾中再設(shè)置一個(gè)__ init__.py,此時(shí)則這個(gè)modules就是一個(gè)程序包仗岸,然后在這個(gè)文件夾里我可以放上我的各種python功能文件也就是定義各種模塊比如基本的deletes.py允耿,mkdirs.py,...`,里面簡(jiǎn)單寫點(diǎn)代碼
import os
def dels(path):
? ? a=os.path.exists(path)
? ? if a:
? ? ? ? if os.path.isdir(path):
? ? ? ? ? ? b=os.listdir(path)
? ? ? ? ? ? if len(b)!=0:
? ? ? ? ? ? ? ? for i in b :
? ? ? ? ? ? ? ? ? ? k=os.path.join(path,i)
? ? ? ? ? ? ? ? ? ? isfile=os.path.isfile(k)
? ? ? ? ? ? ? ? ? ? if isfile:
? ? ? ? ? ? ? ? ? ? ? ? os.remove(k)
? ? ? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? ? ? dels(k)
? ? ? ? ? ? ? ? os.rmdir(path)
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? os.rmdir(path)
? ? ? ? else:
? ? ? ? ? ? os.remove(path)
import os
def mkdirs():
? if not os.path.exists("hy"):
? ? ? os.mkdir("hy")
? ? ? for i in range(100):
? ? ? ? ? a=str(i)
? ? ? ? ? j=os.path.join("hy",a)
? ? ? ? ? with open(j,"wb") as f_w:
? ? ? ? ? ? ? f_w.write(j.encode())`
這樣我的一個(gè)小工具包就完成了扒怖。较锡。。
2.2 包和模塊的復(fù)用
? ? ? ? ? ? python中包和模塊主要是為了自己之前實(shí)現(xiàn)的功能的重用盗痒,最主要的目的是為了有效的整理代碼來(lái)實(shí)現(xiàn)服用性能
? ? ? ? ? 封裝好的包和模塊的代碼被引入使用蚂蕴,仿佛借用一般,不用那么麻煩的重寫等等
? 2.2.1? import 和from .. import
? ? ? ? 1.import 包/模塊
? ? ? ? ? #引入方式
? ? ? ? ? import 模塊
? ? ? ? ? #使用模塊中的數(shù)據(jù)
? ? ? ? ? 模塊.變量
? ? ? ? ? 模塊.函數(shù)
? ? ? ? ? 模塊.類型
? ? ? ? ? remark:import 方式可以引入包俯邓,模塊
? ? ? ? ? import引入的包和模塊會(huì)自動(dòng)從當(dāng)前文件夾骡楼,系統(tǒng)環(huán)境變量pythonpath中,以及sys.path 路徑中查詢是否存在
? ? ? ? ? 如果不存在稽鞭,就會(huì)出現(xiàn)錯(cuò)誤:no module named “xxxx”
2.from 包/模塊 import 具體對(duì)象
? 基本語(yǔ)法如下
? from . import xxx #從當(dāng)前模塊路徑下引入xxx模塊
? from .. import xxx #從當(dāng)前模塊的父級(jí)路徑下引入xxx模塊
? from PKG import module #從PKG包中引入一個(gè)模塊module
? from PKG.module import vars鸟整,func,clazz #從指定模塊中直接引入
? remark:from xx import 語(yǔ)法方式川慌,主要是針對(duì)出現(xiàn)了包結(jié)構(gòu)的python代碼而特定的代碼引入方式吃嘿,首先要非常明確代碼的組織結(jié)構(gòu)才能正確私用from import 語(yǔ)法進(jìn)行代碼的引入和復(fù)用
? remarkl裟恕:通過(guò)上述代碼梦重,可以看到from import 語(yǔ)法區(qū)分為兩種操作
? 1.使用了./..的相對(duì)路徑的引入操作方式
? 2.直接使用包/模塊名稱的絕對(duì)引入操作方式
? 包的引入可以通過(guò)相對(duì)路徑直接操作,包既可以是python的包亮瓷,也可以是一個(gè)普通包含python代碼的文件夾
? 需要注意的是琴拧,一旦使用相對(duì)路徑,就要明確所謂相對(duì)路徑是依賴它們所屬的父級(jí)文件夾嘱支,相當(dāng)于在一個(gè)屋檐下蚓胸,兄弟姐妹一樣,執(zhí)行代碼的時(shí)候需要在命令行中告訴python解釋器在路徑中 python -m hy01.main
? 如果直接在文件夾中執(zhí)行命令 python main.py 就會(huì)出現(xiàn) importerror:cannot import name “(所引入的module)”
? 切記:引入路徑相對(duì)于當(dāng)前文件除师,執(zhí)行路徑相對(duì)于引入的最外層文件夾沛膳,這樣才能正確使用相對(duì)引入操作執(zhí)行我們的模塊代碼。
? 絕對(duì)引入的操作方式比較簡(jiǎn)單汛聚,從最外層的包的源頭直接開(kāi)始操縱
? 如:from pygame import K_A ,K_S,K_D,K_W
? 慣用方式為第三方的模塊操作锹安,在獨(dú)立項(xiàng)目開(kāi)發(fā)較少
? 運(yùn)行操作,和以上的都類似。叹哭。忍宋。
3? 解釋包和模塊
? 模塊:
? python中的模塊,指代的就是一個(gè)python文件
? 1风罩,在一個(gè)python模塊中可以包含的數(shù)據(jù)有:變量糠排,函數(shù),類型等超升,是一個(gè)完整的獨(dú)立代碼塊
? 2入宦,獨(dú)立的一個(gè)代碼塊中的變量:全局變量,局部變量室琢,能被其他模塊引入使用的只有當(dāng)前模塊中的全局變量云石,其他模塊對(duì)于當(dāng)前模塊中的全局變量的操作和普通變量一致
? 3,模塊一旦被其他模塊引入研乒,就會(huì)自動(dòng)執(zhí)行模塊張的所有代碼
? 4汹忠,模塊中的測(cè)試代碼可以包含在if __name__=="__main__":語(yǔ)句塊中,這樣就不在引入的時(shí)候執(zhí)行測(cè)試代碼
? 標(biāo)準(zhǔn)模塊定義方式如下:
? # coding:utf—8
? #引入系統(tǒng)標(biāo)準(zhǔn)模塊
? #引入第三方模塊
? #引入自定義開(kāi)發(fā)模塊
? #聲明定義變量
? #聲明定義函數(shù)
? #聲明定義類型
? #當(dāng)前模塊測(cè)試代碼
? if? __name__=="__main__":
? #測(cè)試代碼位置雹熬,其他模塊引入不會(huì)執(zhí)行這里的代碼
? 包:
? python解釋器在執(zhí)行處理代碼時(shí)宽菜,會(huì)默認(rèn)將包含python文件的文件夾處理為默認(rèn)包,默認(rèn)包只具備文件路徑關(guān)聯(lián)的
? 功能竿报,無(wú)其它功能
? python中的標(biāo)準(zhǔn)包如上铅乡,就是在文件夾中聲明文件__init__.py,這文件夾就是一個(gè)python模塊報(bào)
定義一個(gè)python的數(shù)據(jù)模型包如下:
demo01/
user/
__init__.py #包聲明模塊
modules.py #數(shù)據(jù)類型定義模塊
manager.py #數(shù)據(jù)模型管理模塊
menus.py # 界面處理模塊
main.py #程序主模塊?
需要注意的是 import 包 相當(dāng)于 導(dǎo)入 import 包.__init__.py 但是不能這么寫而已
from 包 import * 是將? 在__init__.py中的__all__包含的模塊一次性引入 __all__=[.......]相當(dāng)于
from 包 import ., ., .,.....
? python中的Main方法
? 由于python是沒(méi)有main方法的不像c++之類的
? 因此我覺(jué)得這個(gè)相當(dāng)于是一個(gè)入口 告訴它要不要執(zhí)行當(dāng)前python文件的測(cè)試代碼
? 大部分人都喜歡這么寫 烈菌,好巧? 我也喜歡? 所以沒(méi)辦法
? 不寫這個(gè)的后果一瞬間會(huì)引入不光你需要的東西阵幸,而且會(huì)有文件中的測(cè)試代碼,所以芽世,一般還是加上為好