python - 模塊使用詳解

微信公眾號搜索【程序媛小莊】灰署,關注半路出家的程序媛如何靠python開發(fā)養(yǎng)家糊口~

前言

Python有非常強大的第三方庫,也有非常多的內(nèi)置模塊幫助開發(fā)人員實現(xiàn)某些功能为鳄,無需開發(fā)人員自己造輪子裳仆。本文介紹Python的模塊。

什么是模塊

模塊簡單來說就是一系列功能的集合體孤钦,如果將程序的開發(fā)比喻成拼圖歧斟,模塊就是各種各樣的拼圖的碎片,準備好拼圖碎片后偏形,剩下的工作就是將需要的碎片按照順序拼起來静袖。

在Python中,一個py文件就是一個模塊俊扭,Python中的模塊分為三種队橙,分別是:

  1. 內(nèi)置模塊 - Python解釋器自帶
  2. 第三方模塊 - 需要手動安裝
  3. 自定義模塊 - 比如一個python文件

為啥要使用模塊

自定義模塊:可以將程序中的公用功能抽取出來放到一個模塊中供大家使用,減少了代碼冗余的前提下還能夠使程序組織結構更加清晰萨惑。

內(nèi)置模塊和第三方模塊:安裝后直接使用模塊的相關功能捐康,無需自己造輪子,可以極大的提升開發(fā)效率庸蔼。

自定義模塊

自定義模塊也是py文件解总,可以作為普通的python腳本執(zhí)行,也可以作為模塊來使用姐仅。比如新建一個test.py花枫,該文件既是腳本程序也是一個模塊刻盐,test就是模塊名。

# test.py
x = 100
print(x)
def get():
    print(x)
    
def change():
    global x
    x = 0

自定義模塊的使用

import語句

想要在其他文件中引用test.py中的數(shù)據(jù)和函數(shù)劳翰,可以使用import 模塊名 進行模塊導入隙疚,其他文件首次導入模塊的時候會分為三步:

首先,執(zhí)行模塊文件中的代碼磕道;

然后供屉,產(chǎn)生一個新的名稱空間用來存放執(zhí)行模塊文件過程中產(chǎn)生的名字;

最后溺蕉,在當前執(zhí)行文件所在的名稱空間中產(chǎn)生一個名字就是導入的模塊名伶丐,該名字會指向模塊執(zhí)行時產(chǎn)生的名稱空間,如果想要引用模塊名稱空間的名字疯特,需要加上前綴用來區(qū)分當前文件的名稱空間與模塊的名稱空間哗魂,防止名字的混淆。

具體代碼如下:

import test  # import的語法是:import 模塊名
# 引用test模塊中的x漓雅,賦值給a變量
a = test.x
print(a)  # 1

# 調用test模塊中的change函數(shù)
test.change()

加上test.作為前綴就相當于指名道姓的說明要引用test名稱空間中的名字录别,所以肯定不會與當前執(zhí)行文件所在名稱空間中的名字相沖突,并且若當前執(zhí)行文件的名稱空間中存在x邻吞,執(zhí)行test.change()操作的都是模塊文件中的全局變量x组题。

需要注意的是,在導入模塊時只有第一次導入時會執(zhí)行模塊中的代碼將其加載到內(nèi)存空間抱冷,之后重復的導入直接引用內(nèi)存中已存在的模塊崔列,不會重復執(zhí)行。

使用import導入多個模塊時可以書寫多行import語句旺遮。

import module1
import module2
...

也可以通過import一行導入赵讯,將不同模塊用逗號隔開。

import module1, module2....

雖然兩種格式都可以耿眉,但是前一種形式更加規(guī)范边翼,推薦使用。在一個py文件中可能會包含多種模塊鸣剪,內(nèi)置模塊组底、第三方模塊、自定義模塊西傀,為了增加代碼可讀性以及更好的符合PEP8規(guī)范(python開發(fā)中編寫代碼的規(guī)范)通常在文件開頭導入模塊斤寇,并且將三種不同模塊中間用空行隔開。

import python內(nèi)置模塊
import python內(nèi)置模塊

import 第三方模塊
import 第三方模塊

import 自定義模塊
import 自定義模塊

from...import語句

from 模塊名 import 名字拥褂,也可以實現(xiàn)導入模塊娘锁,不同的是import 模塊名 導入模塊后,引用模塊中的名字都需要加上模塊名.作為前綴饺鹃,而使用from 模塊名 import 名字則可以在當前執(zhí)行文件中直接引用模塊中的名字莫秆,如下:

from test import x, change  # 將模塊test名稱空間中的x和change導入到當前名稱空間

b = x  # 將模塊test中的x賦值給b
change()  # 執(zhí)行test模塊中的change方法间雀,修改的是模塊中的x變量

這種方式在引用其他自定義模塊的名字時不需要加模塊名的前綴,使代碼更加整潔镊屎,但是缺點也很明顯惹挟,就是容易和當前py文件的名稱空間中的名字沖突。

另外此種導入模塊的方式也支持如下寫法缝驳,表示將模塊中所有的名字都導入到當前位置连锯。

from 模塊名 import *

使用此種導入模塊的方式導入模塊也會發(fā)生三件事:

首先,運行模塊中的代碼用狱;

然后运怖,運行模塊文件將運行過程中產(chǎn)生的名字都放到模塊的名稱空間;

最后夏伊,被當前文件引用的模塊中的名字也會導入到當前文件的名稱空間摇展,這些名字分別指向被導入的模塊名稱空間中的某一個內(nèi)存地址。

兩種導入方式對比

優(yōu)缺點 import 模塊名 from 模塊名 import 名字
優(yōu)點 肯定不會與當前名稱空間的名字沖突 不加前綴溺忧,代碼更精簡
缺點 加前綴顯得代碼不簡潔 容易與當前名稱空間的名字混淆

其他語法 - as

可以為導入的模塊起一個別名咏连,例如:

import test as t

print(t.x)
t.change()

也可以為導入的名字起別名,例如:

from test import change as change_x

change_x()

當被導入的名字過長時就可以使用起別名的方式來精簡代碼鲁森,而且起別名可以很好地避免與當前文件的名稱空間中的名字發(fā)生沖突祟滴。

循環(huán)導入

循環(huán)導入的問題指的是在一個模塊加載/導入的過程中導入另外一個模塊,而另一個模塊中又返回來導入第一個模塊中的名字刀森,由于第一個模塊尚未加載完畢踱启,所以引用失敗报账,拋出異常研底。以下述文件為例分析循環(huán)導入出現(xiàn)的異常的原因及解決方案。

image-20210528231810671

如果直接運行module1.py或者module2.py同樣也會報錯透罢,報錯的原因都是由于循環(huán)導入榜晦。解決循環(huán)導入問題有以下兩種方案:

第一種羽圃,將導入語句放到代碼最后朽寞,保證在導入的時候脑融,模塊中的所有名字都已經(jīng)加載到名稱空間中肘迎。

image-20210529095844571

第二種,將導入語句放到函數(shù)中宋梧,只有調用函數(shù)時才會執(zhí)行其內(nèi)部代碼捂龄。

image-20210529100518651

這里需要補充一點,理論上來講殉农,在函數(shù)內(nèi)導入模塊愈污,這個模塊是在局部名稱空間的暂雹,當函數(shù)調用結束之后模塊對應的名稱空間應該被回收杭跪,但是當函數(shù)調用結束之后涧尿,再次導入模塊姑廉,模塊文件卻不會運行桥言。如下述代碼:

def test():
    import foo  # 在函數(shù)內(nèi)導入模塊
test()

import foo  # 執(zhí)行函數(shù)后号阿,再次導入扔涧,發(fā)現(xiàn)已經(jīng)不會運行模塊文件了粉铐,說明不是第一次導入

print(sys.modules)  # 查看加載到內(nèi)存中的模塊

產(chǎn)生這種現(xiàn)象的原因:python解釋器內(nèi)部優(yōu)化機制蝙泼,默認導入的模塊在執(zhí)行文件中會被大量使用汤踏,所以即便是在局部名稱空間中也不會被回收溪胶。

循環(huán)導入問題大多數(shù)情況下都是因為程序設計失誤導致的哗脖,上述方案也只是在設計失誤額前提下的無奈之舉才避,在設計程序的時候應盡可能避免出現(xiàn)循環(huán)導入的問題桑逝。

查找模塊路徑及優(yōu)先級

無論是import 還是from...import...導入模塊都涉及到查找模塊路徑的問題楞遏,模塊查找順序按照如下規(guī)則進行:

首先寡喝,在內(nèi)存中查找拘荡,在導入一個模塊時,如果該模塊已經(jīng)加載到內(nèi)存中巨税,就直接引用草添≡洞纾可以通過導入sys模塊(import sys)驰后,打印sys.modules查看已經(jīng)加載到內(nèi)存中的模塊名稱郑原。

然后犯犁,如果內(nèi)存中沒有,再去查找內(nèi)置模塊簇捍。

最后暑塑,如果內(nèi)置模塊中沒有事格,就按照從左到右的順序依次檢索sys.path(稱為模塊的搜索路徑,是一個列表)中的路徑,直到找到模塊對應的文件劫瞳,否則拋出異常。

通過下面的例子伺绽,來說明模塊查找的優(yōu)先級:創(chuàng)建一個test.py文件作為模塊澜掩,創(chuàng)建一個run.py文件作為執(zhí)行文件肩榕。

在執(zhí)行文件休息10s的時間內(nèi)点把,快速將模塊文件foo.py刪除,10s結束后再次調用foo.py中的foo函數(shù),如果能夠調用成功优训,那么就說明是在內(nèi)存中導入的foo文件。經(jīng)過驗證,10s后的foo函數(shù)可以被調用搞监,但是如果重新運行執(zhí)行文件就會報錯,提示沒有foo模塊。

# test.py
def test():
    print('我是test')
print('test')

# run.py
import time
from test import test

test()
time.sleep(10)
test()  

如果內(nèi)存中沒有找到模塊够委,也不屬于內(nèi)置模塊,就按照從左到右的順序依次檢索sys.path列表中路徑下的文件。需要注意的是,sys.path在pycharm和python解釋器中得到的結果不同,使用pycharm查看sys.path時會將當前項目路徑自動加入到sys.path列表中。

# pycharm運行結果
import sys
print(sys.path)

['F:\\FullStack\\Python_based', 'F:\\FullStack\\Python_based', 'E:\\python3.9\\python39.zip', 'E:\\python3.9\\DLLs', 'E:\\python3.9\\lib', 'E:\\python3.9', 'E:\\python3.9\\lib\\site-packages']


# python解釋器運行結果
>>> import sys
>>> sys.path

['', 'E:\\python3.9\\python39.zip', 'E:\\python3.9\\DLLs', 'E:\\python3.9\\lib', 'E:\\python3.9', 'E:\\python3.9\\lib\\site-packages']

使用python解釋器得到的sys.path的結果第一個元素通常為空,代表執(zhí)行文件所在的路徑鲸匿,所以在被導入模塊與執(zhí)行文件在同一目錄下時肯定是可以正常導入的,而針對被導入的模塊與執(zhí)行文件在不同路徑下的情況洪囤,為了確保模塊對應的源文件仍可以被找到徒坡,需要將模塊文件所在的路徑添加到sys.path中,假設模塊文件test.py所在的路徑為D:/modules瘤缩。

import sys

sys.path.append(r'D:/modules')  # 也可以使用insert方法
import test

py文件的兩種用途

一個py文件有兩種用途喇完,一種是當做程序或者腳本執(zhí)行,另一種是被當做模塊剥啤,為了區(qū)分同一個py文件的不同用途锦溪,每個py文件都內(nèi)置了__name__變量,該變量在py文件被當做腳本執(zhí)行時賦值為__main__府怯,在py文件被當做模塊導入時賦值為模塊名刻诊。

可以在模塊文件的末尾基于__name__來測試模塊功能代碼,當文件被當做腳本運行時牺丙,會執(zhí)行if后的代碼塊则涯,當做模塊導入時則不執(zhí)行复局。

# test.py
...  # 代碼
...  # 代碼

if __name__ == '__main__':
    test.py被當做腳本文件執(zhí)行時運行的代碼
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市粟判,隨后出現(xiàn)的幾起案子亿昏,更是在濱河造成了極大的恐慌,老刑警劉巖档礁,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件角钩,死亡現(xiàn)場離奇詭異,居然都是意外死亡呻澜,警方通過查閱死者的電腦和手機递礼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來羹幸,“玉大人脊髓,你說我怎么就攤上這事《糜” “怎么了供炼?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長窘疮。 經(jīng)常有香客問我袋哼,道長,這世上最難降的妖魔是什么闸衫? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任涛贯,我火速辦了婚禮,結果婚禮上蔚出,老公的妹妹穿的比我還像新娘弟翘。我一直安慰自己,他們只是感情好骄酗,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布稀余。 她就那樣靜靜地躺著,像睡著了一般趋翻。 火紅的嫁衣襯著肌膚如雪睛琳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天踏烙,我揣著相機與錄音师骗,去河邊找鬼。 笑死讨惩,一個胖子當著我的面吹牛辟癌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荐捻,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼黍少,長吁一口氣:“原來是場噩夢啊……” “哼寡夹!你這毒婦竟也來了?” 一聲冷哼從身側響起仍侥,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤要出,失蹤者是張志新(化名)和其女友劉穎鸳君,沒想到半個月后农渊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡或颊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年砸紊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片囱挑。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡醉顽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出平挑,到底是詐尸還是另有隱情游添,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布通熄,位于F島的核電站唆涝,受9級特大地震影響,放射性物質發(fā)生泄漏唇辨。R本人自食惡果不足惜廊酣,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赏枚。 院中可真熱鬧亡驰,春花似錦、人聲如沸饿幅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栗恩。三九已至透乾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間摄凡,已是汗流浹背续徽。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留亲澡,地道東北人钦扭。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像床绪,于是被迫代替她去往敵國和親客情。 傳聞我的和親對象是個殘疾皇子其弊,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容