第8章 模塊
第8章 模塊
8.1 模塊概述
模塊的英文是Modules,可以認為是一盒(箱)主題積木,通過它可以拼出某一個主題的東西。這與第6章介紹的函數不同,一個函數相當於一塊積木,而一個模塊中可以包括很多函數,也就是很多積木,所以也可以說模塊相當於一盒積木。
在Python中,一個拓展名為“.py”的文件就稱之為一個模塊。
通常情況下,我們把能夠實現某一特定功能的代碼放置在一個文件中作為一個模塊,從而方便其他程序和腳本導入並使用。另外,使用模塊也可以避免函數名和變量名沖突。
經過前面的學習,我們知道對於Python代碼可以寫到一個文件中。但是隨著程序不斷變大,為了便於維護,需要將其分為多個文件,這樣可以提高代碼的可維護性。另外,使用模塊還可以提高代碼的可重用性。即編寫好一個模塊後,只要是實現該功能的程序,都可以導入這個模塊實現。
8.2 自定義模塊
在Python中,自定義模塊有兩個作用:一個是規範代碼,讓代碼更易於閱讀,另一個是方便其他程序使用已經編寫好的代碼,提高開發效率。
實現自定義模塊主要分為兩部分,一部分是創建模塊,另一個部分是導入模塊。
8.2.1 創建模塊
創建模塊時,可以將模塊中相關的代碼(變量定義和函數定義等)編寫在一個單獨的文件中,並且將該文件命名為“模塊名+.py”的形式。
註意:創建模塊時,設置的模塊名不能是Python自帶的標準模塊名稱。
實例01:創建計算BMI指數的模塊
def fun_bmi(person,height,weight):‘‘‘功能:根據身高和體重計算BMI指數 person:姓名 height:身高,單位:米 weight:體重,單位:千克 ‘‘‘ print(person + "的身高:" + str(height) + "米\t體重:" + str(weight) + "千克") bmi=weight/(height*height) # 用於計算BMI指數,公式為:BMI=體重/身高的平方 print(person + "的BMI指數為:"+str(bmi)) # 輸出BMI指數 # 此處省略了顯示判斷結果的代碼 def fun_bmi_upgrade(*person): ‘‘‘功能:根據身高和體重計算BMI指數(升級版) *person:可變參數該參數中需要傳遞帶3個元素的列表, 分別為姓名、身高(單位:米)和體重(單位:千克) ‘‘‘ # 此處省略了函數主體代碼
註意:模塊文件的擴展名必須是“.py”。
8.2.2 使用import 語句導入模塊
創建模塊後,就可以在其他程序中使用該模塊了。要使用模塊需要以模塊的形式加載模塊中的代碼,這可以使用import語句實現。import語句的基本語法格式如下:
import modulename[as alias]
其中,modulename為要導入模塊的名稱;[as alias]為給模塊起的別名,通過該別名也可以使用模塊。
下面將導入實例01所編寫的模塊bmi,並執行該模塊中的函數。在模塊文件bmi.py的同級目錄下創建一個名稱為mai.py的文件,在該文件中,導入模塊bmi,並且執行該模塊中的fun_bmi()函數,代碼如下:
import bmi # 導入bmi模塊 bmi.fun_bmi("大白",1.80,130) # 執行模塊中的fun_bmi()函數
執行上面的代碼,運行結果如下。
大白的身高:1.8米 體重:130千克
大白的BMI指數為:40.123456790123456
說明:在調用模塊中的變量、函數或者類時,需要在變量名、函數名或者類名前添加“模塊名.”作為前綴。例如,上面代碼中的bmi.fun_bmi,表示調用bm i模塊中的fun_bmi() 函數。
多學兩招:
如果模塊名比較長不容易記住,可以在導入模塊時,使用as 關鍵字為其設置一個別名,然後就可以通過這個別名來調用模塊中的變量、函數和類等。例如,將上面導入模塊的代碼修改為以下內容:
import bmi as m # 導入bmi模塊並設置別名為m
然後,在調用bmi 模塊中的fun_bmi() 函數時,可以使用下面的代碼:
m.fun_bmi("大白",1.80,130) # 執行模塊中的fun_bmi()函數
使用import 語句還可以一次導入多個模塊,在導入多個模塊時,模塊名之間使用逗號“,”進行分隔。例如,分別創建了bmi.py、tips.py 和 differenttree.py 3 個模塊文件。想要將這3個模塊全部導入,可以使用下面的代碼:
import bmi,tips,differenttree
8.2.3 使用from...import 語句導入模塊
在使用import 語句導入模塊時,每執行一條import 語句都會創建一個新的命名空間(namespace),並且在該命名空間中執行與.py 文件相關的所有語句。在執行時,需在具體的變量、函數和類名前加上“模塊名.”前綴。如果不想在每次導入模塊時都創建一個新的命名空間,而是將具體的定義導入到當期的命名空間,這時可以使用from...import 語句。使用from...import 語句導入模塊後,不需要在添加前綴,直接通過具體的變量、函數和類名等訪問即可。
說明:命名空間可以理解我記錄對象名字和對象之間對應關系的空間。目前Python的命名空間大部分都是通過字典(dict)來實現的。其中,key 是標識符;value 是具體的對象。例如,key 是變量的名字,value 則是變量的值。
from...import 語法格式如下:
from modelname import member
參數說明:
- modelname:模塊名稱,區分字母大小寫,需要和定義模塊時設置的模塊名稱大小寫保存一致。
- member:用於指定要導入的變量、函數或者類等。可以同時導入多個定義,各個定義之間使用逗號“.” 分隔。如果想導入全部定義,也可以使用通配符號“*” 代替。
多學兩招:在導入模塊時,如果使用通配符“*” 導入全部定義後,想查看具體導入了哪些定義,可以通過顯示dir() 函數的值來查看。例如,執行print(dir()) 語句後將顯示類似下面的內容。
[‘__annotations__‘, ‘__builtins__‘, ‘__doc__‘, ‘__file__‘, ‘__loader__‘, ‘__name__‘, ‘__package__‘, ‘__spec__‘, ‘m‘]
……
例如,通過下面的3 條語句都可以從模塊導入指定的定義。
from bmi import fun_bmi # 導入bmi模塊的fun_bmi函數 from bmi import fun_bmi,fun_bmi_uparade # 導入bmi模塊的fun_bmi和fun_upgrade函數 from bmi import * # 導入bmi模塊的全部定義(包括變量和函數)
註意:在使用from...import 語句導入模塊中的定義時,需要保證所導入的內容在當前的命名空間中是唯一的,否則將出現沖突,後導入的同名變量、函數或者會覆蓋先導入的。這時就需要使用import語句進行導入。
實例02:導入兩個包括同名函數的模塊
創建兩個模塊,一個是矩形模塊,其中包括計算矩形周長和面積的函數;另一個是圓形,其中包括計算圓形周長和面積的函數。然後在另一個Python文件中導入這兩個模塊,並調用相應的函數計算周長的面積。具體步驟如下:
(1)創建矩形模塊,對應的文件名為rectangle.py,在該文件中定義兩個函數,一個用於計算矩形的周長,另一個用於計算矩形的面積,具體代碼如下:
def firth(width,height): ‘‘‘功能:計算周長 參數:width(寬度)、height(高) ‘‘‘ return(width + height)*2 def area(width,height): ‘‘‘功能:計算面積 參數:width(寬度)、height(高) ‘‘‘ return width * height if __name__ == ‘__main__‘: print(area(10,20))
(2)創建圓形模塊,對應的文件名稱為circular.py,在該文件中定義兩個函數,一個用於計算圓形的周長,另一個用於計算圓形的面積,具體代碼如下:
import math # 導入標誌模塊math PI = math.pi # 圓周率 def girth(r): ‘‘‘功能:計算周長 參數:r(半徑) ‘‘‘ return round(2 * PI * r ,2 ) # 計算周長並保留兩位小數 def area(r): ‘‘‘功能:計算面積 參數:r(半徑) ‘‘‘ return round(PI * r * r ,2 ) # 計算面積並保留兩位小數 if __name__ == ‘__main__‘: print(girth(10))
(3)創建一個名稱為compute.py 的Python文件,首先導入矩形模塊的全部定義,然後導入圓形模型的全部定義,最後分別調用計算矩形周長的函數和計算圓形周長的函數,代碼如下:
from rectangle import * # 導入矩形模塊 from circular import * # 導入圓形模塊 if __name__ == ‘__main__‘: print(‘圓形的周長為:‘,girth(10)) # 調用計算圓形周長的函數 print(‘矩形的周長為:‘,area(10,20)) # 調用計算矩形周長的函數
執行compute.py文件,將顯示如下結果。
圓形的周長為: 62.83 Traceback (most recent call last): File "D:\python3.6.5\練習文件\main.py", line 11, in <module> print(‘矩形的周長為:‘,girth(10,20)) # 調用計算矩形周長的函數 TypeError: girth() takes 1 positional argument but 2 were given
從圖中可以看出執行步驟(3)的第5行代碼時出現異常,這是因為原本想執行的矩形模塊的girth() 函數被圓形模塊的girth() 函數給蓋住了。解決該問題的方法是,不使用from...import 語句導入,而是使用import 語句導入。修改後的代碼如下:
import rectangle as r # 導入矩形模塊 import circular as c # 導入圓形模塊 if __name__ == ‘__main__‘: print(‘圓形的周長為:‘,c.girth(10)) # 調用計算圓形周長的函數 print(‘矩形的周長為:‘,r.area(10,20)) # 調用計算矩形周長的函數
運行結果如下:
圓形的周長為: 62.83
矩形的周長為: 200
8.2.4 模塊搜索目錄
當使用import 語句導入模塊時,默認情況下,會按照以下順序進行查找。
(1)在當前目錄(即執行的Python 腳本文件所在目錄)下查找。
(2)到PYTHONPATH(環境變量)下的每個目錄中查找。
(3)到Python 的默認安裝目錄下查找。
以上各個目錄的具體位置保存在標準模塊sys 的sys.path 變量中。可以通過以下代碼輸出具體的目錄。
import sys # 導入標準模塊sys print(sys.path) # 輸出具體目錄
……
註意:使用import 語句導入模塊時,模塊名是區分字母大小寫的。
這時,我們可以通過以下3 種方式添加指定的目錄到sys.path 中。
1. 臨時添加
臨時添加即在導入模塊的Python 文件中添加。
2. 增加.pth文件(推薦)
註意:創建.pth 文件後,需要重新打開要執行的導入模塊的Python 文件,否則新添加的目錄不起作用。
說明:通過該方法添加的目錄只在當前版本的Python 中有效。
3. 在PYTHONPATH 環境變量中添加
說明:通過該方法添加的目錄可以在不同版本的Python 中共享。
8.3 以主程序的形式執行
這裏先來創建一個模塊,名稱為christmastree,該模塊的內容為第6章中的編寫的實例05的代碼。該段代碼中,首先定義一個全局變量,然後創建一個名稱為fun_christmastree() 的函數,最後在通過print() 函數輸出一些內容。代碼如下:
pinetree = ‘我是一棵松樹‘ # 定義一個全局變量(松樹) def fun_christmastree(): # 定義函數 ‘‘‘功能:一個夢 無返回值 ‘‘‘ pinetree = ‘掛上彩燈、禮物……我變成一棵聖誕樹 @^.^@ \n‘ # 定義局部變量 print(pinetree) # 輸出局部變量的值 #**************************函數體外*****************************# print(‘\n下雪了……\n‘) print(‘=============開始做夢……==============\n‘) fun_christmastree() # 調用函數 print(‘=============夢醒了……==============\n‘) pinetree = ‘我身上落滿雪花,‘+ pinetree + ‘-_-‘ # 為全局變量賦值 print(pinetree) # 輸出全局變量的值
在與Christmastree 模塊同級的目錄下,創建一個名稱為main.py 的文件,在該文件中,導入christmastree 模塊,再通過print() 語句輸出模塊中的全局變量pinetree 的值,代碼如下:
import christmastree # 導入Christmastree模塊 print("全局變量的值為:",christmastree.pinetree)
執行上面的代碼,顯示結果如下:
下雪了…… =============開始做夢……============== 掛上彩燈、禮物……我變成一棵聖誕樹 @^.^@ =============夢醒了……============== 我身上落滿雪花,我是一棵松樹-_- 全局變量的值為: 我身上落滿雪花,我是一棵松樹-_- >>>
從上的運行結果可以看出,導入模塊後,不僅輸出了全局變量的值,而且模塊中原有的測試代碼也被執行了。這個結果顯然不是我們想要的。那麽如何輸出全局變量的值呢?實際上,可以在模塊中,將原本直接執行的代碼放在一個if 語句中。因此,可以將模塊Christmastree 的代碼修改為以下內容:
pinetree = ‘我是一棵松樹‘ # 定義一個全局變量(松樹) def fun_christmastree(): # 定義函數 ‘‘‘功能:一個夢 無返回值 ‘‘‘ pinetree = ‘掛上彩燈、禮物……我變成一棵聖誕樹 @^.^@ \n‘ # 定義局部變量 print(pinetree) # 輸出局部變量的值 #**************************函數體外*****************************# if __name__==‘__main__‘: print(‘\n下雪了……\n‘) print(‘=============開始做夢……==============\n‘) fun_christmastree() # 調用函數 print(‘=============夢醒了……==============\n‘) pinetree = ‘我身上落滿雪花,‘+ pinetree + ‘-_-‘ # 為全局變量賦值 print(pinetree) # 輸出全局變量的值
再次執行導入模塊的main.py 文件,可以看出示測試代碼並沒有執行。
全局變量的值為: 我是一棵松樹
此時,如果執行christmastree.py 文件,結果如下:
下雪了…… =============開始做夢……============== 掛上彩燈、禮物……我變成一棵聖誕樹 @^.^@ =============夢醒了……============== 我身上落滿雪花,我是一棵松樹-_-
說明:在每個模塊的定義中都包括一個記錄模塊名稱的變量__name__,程序可以檢查該變量,以確定它們在哪個模塊中執行。如果一個模塊不是被導入到其他程序中執行,那麽它可能在解釋器的頂級模塊中執行。頂級模塊的__name__變量的值為__main__。
8.4 Python中的包
使用模塊可以避免函數名和變量名重名引發的沖突。那麽,如果模塊名重復應該怎麽辦呢?在Python中,提出了包(Package)的概念。包是一個分層次的目錄結構,它將一組功能相近的模塊組織在一個目錄下。這樣,既可以起到規範代碼的作用,又能避免模塊名重名引起的沖突。
說明:包簡單的理解就是“文件夾”,只不過在該文件夾下必須存在一個名稱為“__init__.py”的文件。
8.4.1 Python程序的包結構
在實際項目開發時,通常情況下,會創建多個包用於存放不同類的文件。
8.4.2 創建和使用包
下面將分別介紹如何創建和使用包。
1. 創建包
創建包實際上就是創建一個文件夾,並且在該文件夾中創建一個名稱為“__init__.py”的Python文件。在__init__.py文件中,可以不編寫任何代碼,也可以編寫一些Python代碼。在__init__.py文件中所編寫的代碼,在導入包時會自動執行。
說明:__init__.py文件是一個模塊文件,模塊名稱對應的包名。例如,在settings包中創建的__init__.py文件,對應的模塊名為settings。
至此,名稱為settings的包創建完畢了,創建完畢之後便可以在該包中創建所需的模塊了。
2. 使用包
創建包以後,就可以在包中創建相應的模塊,然後再使用import語句從包中加載模塊。從包中加載模塊通常有以下3 種方式:
- 通過“import+完整包名+模塊名”形式加載指定模塊
通過“import+完整包名+模塊名”形式是指:假如有一個名稱為settings的包,在該包下有一個名稱為size 的模塊,那麽要導入size 模塊,可以使用下面的代碼:
import settings.size
通過該方式導入模塊後,在使用時需要使用完整的名稱。例如,在已經創建的settings包中創建一個名稱為size的模塊,並且在該模塊中定義兩個變量,代碼如下:
width = 800 # 寬度 heigtht = 600 # 高度
這時,通過“import+完整包名+模塊名”形式導入size模塊後,在調用width和height變量時,就需要在變量名前加入“settings.size”前綴。對應的代碼如下:
import settings.size # 導入settings包下的size模塊 if __name__==‘__main__‘: print(‘寬度:‘,settings.size.width) print(‘高度:‘,settings.size.height)
執行上面的代碼後,將顯示以下內容:
寬度: 800
高度: 600
- 通過“from+完整包名+import+模塊名”形式加載指定模塊
“from+完整包名+import+模塊名”形式是指:假如有一個名稱為settings的包,在該包下有一個名稱為size的模塊,那麽要導入size模塊,可以使用下面的代碼:
form settings import size
通過該方式導入模塊後,在使用時不需要帶包前綴,但是需要帶模塊名。例如,想通過“from+完整包名+import+模塊名”形式導入上面已經創建的size模塊,並且調用width和height變量,就可以通過下面的代碼實現:
from settings import size # 導入settings包下的size模塊 if __name__==‘__main__‘: print(‘寬度:‘,size.width) print(‘高度:‘,size.height)
執行上面的代碼後,將顯示以下內容:
寬度: 800
高度: 600
- 通過“from+完整包名+模塊名+import+定義名”形式加載指定模塊
“from+完整包名+模塊名+import+定義名”形式是指:加入有一個名稱為settings的包,在該包下有一個名稱為size的模塊,那麽要導入size模塊中的width和height變量,可以使用下面的代碼:
from settings.size import width,height
通過該方式導入模塊的函數、變量或類後,在使用時直接使用函數、變量或類名即可。例如,想通過“from+完整包名+模塊名+import+定義名”形式導入上面已經創建的size模塊的width和height,並輸出,就可以通過下面的代碼實現:
# 導入settings包下size模塊中的width和height變量 from settings.size import width,height if __name__==‘__main__‘: print(‘寬度:‘,width) # 輸出寬度 print(‘高度:‘,height) # 輸出高度
執行上面的代碼後,將顯示以下內容:
寬度: 800
高度: 600
說明:在通過“from+完整包名+模塊名+import+定義名”形式加載指定模塊時,可以使用星號“*” 代替定義名,表示加載該模塊下的全部定義。
實例03:在指定包中創建通過的設置和獲取尺寸的模塊
創建一個名稱為settings 的包,在該包下創建一個名稱為size的模塊,通過該模塊實現設置和獲取尺寸的通用功能。具體步驟如下:
(1)在settings包中,創建一個名稱為size的模塊,在該模塊中,定義兩個保護類型的的全局變量,分別代表寬度和高度,然後定義一個change()函數,用於修改兩個全局變量的值,在定義兩個函數,分別用於獲取寬度和高度,具體代碼如下:
width = 800 # 定義保護類型的全局變量(寬度) height = 600 # 定義保護類型的全局變量(高度) def change(w,h): global _width # 全局變量(寬度) _width = w # 重新給寬度賦值 global _height # 全局變量(高度) _height = h # 重新給高度賦值 def getWidth(): # 獲取寬度的函數 global _width return _width def getHeight(): # 獲取高度的函數 global _height return _height
(2)在settings 包的上一層目錄中創建一個名稱為main.py的文件,在該文件中導入settings包下的size模塊的全部定義,並且調用change()函數重新設置寬度和高度,然後在分別調用getWidth()和getHeight()函數獲取修改後的寬度和高度,具體代碼如下:
from settings.size import * # 導入size模塊下的全部定義 if __name__==‘__main__‘: change(1024,768) # 調用change()函數改變尺寸 print(‘寬度:‘,getWidth()) # 輸出寬度 print(‘高度:‘,getHeight()) # 輸出高度
執行本實例,顯示結果如下:
寬度: 1024
高度: 768
8.5 引用其他模塊
在Python中,除了可以自定義模塊外,還可以引用其他模塊,主要包括使用標準模塊和第三方模塊。下面分別進行介紹。
8.5.1 導入和使用標準模塊
在Python中,自帶了很多實用的模塊,稱為標準模塊(也可以稱為標準庫),對於標準模塊,我們可以直接使用import語句導入Python文件中使用。例如,導入標準模塊random(用於生成隨機數),可以使用下面的代碼:
import random # 導入標準模塊random
說明:在導入標準模塊時,也可以使用as 關鍵字為其指定別名。通常情況下,如果模塊名比較長,則可以為其設置別名。
導入標準模塊後,可以通過模塊名調用其提供的函數。例如,導入random模塊後,就可以調用randint()函數生成一個指定範圍的隨機數整數。例如,生成一個0~10(包括0和10)的隨機整數的時代代碼如下:
import random # 導入標準模塊random print(random.randint(0,10)) # 輸出0~10的隨機數
執行上面的代碼,可能會輸出0~10 中的任意一個數。
實例04:生成有數字、字母組成的4 位驗證碼
在IDLE 中創建一個名稱為checkcode.py 的文件,然後在該文件中導入Python 標準模塊中random 模塊(用於生成隨機數),然後定義一個保存驗證碼的變量,在應用for 語句實現一個重復4 次的循環,在該循環中,調用random 模塊提供的randrange() 和randint() 方法生成符合要求的驗證碼,最後輸出生成的驗證碼,代碼如下:
import random # 導入標準模塊中的random if __name__==‘__main__‘: checkcode = "" # 保存驗證碼的變量 for i in range(4): # 循環4次 index = random.randrange(0,4) # 生成0~3中的一個數 if index != i and index + 1 != i: checkcode += chr(random.randint(97,122)) # 生成a~z中的一個小寫字母 elif index + 1 == i: checkcode += chr(random.randint(65,90)) # 生成A~Z中的一個大寫字母 else: checkcode += str(random.randint(1,9)) # 生成1~9中的一個數字 print("驗證碼:",checkcode) # 輸出生成的驗證碼
執行本實例,顯示如下結果:
驗證碼: k5Ni
除了random模塊外,Python還提供了大約200多個內置的標準模塊,涵蓋了Python運行時服務、文字模式匹配、操作系統接口、數學運算、對象永久保存、網絡和Internet腳本和GUI構建等方面。
模塊名 | 描述 |
sys | 與Python解釋器及其環境操作相關的標準庫 |
time | 提供與時間相關的各種函數的標準庫 |
os | 提供了訪問湊在哦系統服務功能的標準庫 |
calendar | 提供了與日期相關的各種函數的標準庫 |
urllib | 用於讀取來自網上(服務器上)的數據的標準庫 |
json | 用於使用JSON序列化和反序列化對象 |
re | 用於在字符串中執行正則表達式匹配和替換 |
math | 提供算術運算函數的標準庫 |
decimal | 用於進行精確控制運算精度、有效數位和四舍五入操作的十進制運算 |
shutil | 用於進行高級文件操作,如復制、移動和重命名等 |
logging | 提供了靈活的記錄事件、錯誤、警告和調試信息等日誌的功能 |
tkinter | 使用Python進行GUI編程的標準庫 |
8.5.2 第三方模塊的下載與安裝
在進行Python程序開發時,除了可以使用Python內置的標準模塊外,還有很多第三方模塊可以被我們所使用。對於這些第三方模塊,可以在Python官方推出的http://pypi.python.org/pypi中找到。
在使用第三方模塊時,需要先下載並安裝該模塊,然後就可以像使用標準模塊一樣導入並使用了。本節主要介紹如何下載和安裝。下載和安裝第三方模塊可以使用Python提供的pip命令實現。pip命令的語法格式如下:
pip<command>[modulename]
參數說明:
- command:用於指定要執行的命令。常用的參數值有install(用於安裝第三方模塊)、uninstall(用於卸載已經安裝的第三方模塊)、list(用於顯示已經安裝的第三方模塊)等。
- modulename:可選參數,用於指定要安裝或者卸載的模塊名,當command為install或者uninstall時不能省略。
例如,安裝第三方numpy模塊(用於科學計算),可以在命令行窗口中輸入以下代碼:
pip install mumpy
執行上面代碼,將在線安裝numpy模塊。
註意:添加完環境變量需要重啟命令窗口。
說明:在大型程序中可能需要導入很多模塊,推薦先導入Python提供的標準模塊,然後在導入第三方模塊,最後導入自定義模塊。
多學兩招:如果想要查看Python中的都有哪些模塊(包括標準模塊和第三方模塊),可以在INLE中輸入以下命令:
help(‘modules‘)
如果只是想要查看已經安裝的第三方模塊,可以在命令行窗口中輸入以下命令:
pip list
第8章 模塊