定義模塊、包
在計算機程序的開發過程中,隨着程序代碼越寫越多,在一個文件里代碼就會越來越長,越來越不容易維護。
為了編寫可維護的代碼,我們把很多函數分組,分別放到不同的文件里,
在Python中,一個.py文件就稱之為一個模塊(Module)。
使用模塊有什么好處?
- 最大的好處是大大提高了代碼的可維護性。
- 編寫代碼不必從零開始。當一個模塊編寫完畢,就可以被其他地方引用。
- 使用模塊還可以避免函數名和變量名沖突。相同名字的函數和變量完全可以分別存在不同的模塊中
但是如果不同的人編寫的模塊名相同怎么辦?
為了避免模塊名沖突,Python又引入了按目錄來組織模塊的方法,稱為包(Package)。其他的語言可能就叫“命名空間”
比如一個abc.py的文件就是一個名字叫abc的模塊,如果abc與其他模塊沖突了,可以選擇一個頂層的包mycompany來避免沖突。
那么引用的時候需要注意,是
mycompany.abc而不是abc
另外需要注意的是在每個包目錄下需要有一個
__init__.py,否則會把目錄當做普通的目錄。
init.py可以是空文件,也可以有Python代碼,因為__init__.py本身就是一個模塊,而它的模塊名就是mycompany。
自己創建模塊時要注意命名,不能和Python自帶的模塊名稱沖突
使用模塊
使用內置模塊
比如導入sys模塊:
import sys
導入sys模塊后,我們就有了變量sys指向該模塊,利用sys這個變量,就可以訪問sys模塊的所有功能。
sys模塊有一個argv變量,用list存儲了命令行的所有參數。argv至少有一個元素,因為第一個參數永遠是該.py文件的名稱
使用自定義模塊
導入自定義模塊可以分為靜態導入和動態導入。
靜態導入指的是在文件的開頭的時候使用import語句進行一次導入,動態導入是在需要使用的時候再動態的導入,這樣就可以在runtime的時候導入模塊,而不是在文件的開頭一次性導入,更為靈活。
靜態導入
靜態導入主要通過import或者from語句。
多次import同一個模塊,只有第一次有效。
這兩種語句的區別:
比如下圖中,想導入libs.Model.testModelClass模塊里面的類testModel。
首先需要在Model文件夾下建立__init__.py文件。

- import libs.Model.testModelClass: 這些子項必須是包,最后的子項是包或模塊。但不能為函數、類或變量,所以實際上沒有得到正確的結果。如果想要實例化類,必須將包名寫全,也即
testModelInstance = libs.Model.testModelClass.testModel()。 - from libsModel.testModelClass import testModel:這種方式item可以是包中的一個子模塊或子包,也可以是包中定義的其他命名,像函數、類、變量。所以可以正確引入testModel,可以使用
testModelInstance = testModel()進行實例化。
使用from導入變量,如果和作用域中現有的變量同名,本地變量就會被悄悄地覆蓋掉;使用import則沒這個問題。
動態導入
靜態導入類似常量,只能導入名字已經確定的模塊。但是有這樣一種情況,如果希望定義一個函數,傳入導入的模塊的包和模塊的名稱,然后進行導入,使用靜態導入是不能實現的。
動態導入一般可以使用__import__()函數,等價於import語句。
但是如果要導入模塊中的變量或者類需要結合反射。
先介紹一下getattr()這個python內置函數。
getattr(object, name[,default]):獲取對象object的屬性或者方法
- 如果存在則打印出來
- 如果不存在,打印出默認值,默認值可選。
如果是返回的對象的方法,返回的是方法的內存地址,所以只要在后面添加一對括號,就可以運行這個方法。
比如:
class test():
... name="xiaohua"
... def run(self):
... return "HelloWord"
下面演示一下反射:
>>> t=test()
>>> getattr(t, "name") #獲取name屬性,存在就打印出來。
'xiaohua'
>>> getattr(t, "run") #獲取run方法,存在就打印出方法的內存地址。
那么如果要動態的導入上一節里面的那個例子里面的libs.Model.testModel模塊中的testModelClass應該怎么辦呢?
libs = __import__('libs.Model.testModelClass');#動態的導入
model = getattr(libs , "Model");#通過反射一步一步獲得模塊testModelClass
testModelClass= getattr(model , 'testModelClass');
testModel = getattr( testModelClass, "testModel");#通過反射獲得類testModel
obj = testModel();#實例化類
get = getattr(testModel , "get");#調用testModel類中的get()方法。
get(obj);
有人會說這有什么用?
比如libs.Model下面可能不是testModelClass,可以是authModelClass的模塊,里面的類也相應改變為authModel。那么有沒有辦法定義一個M(name , method),實現的功能是導入libs.Model.authModelClass下的authModel類並進行實例化。同時調用method方法。
def M(name, method):
libs = __import__('libs.Model.'+name+'ModelClass');#動態的導入
model = getattr(libs , "Model");#通過反射一步一步獲得模塊testModelClass
testModelClass= getattr(model , name+'ModelClass');
testModel = getattr( testModelClass, name+"Model");#通過反射獲得類testModel
obj = testModel();#實例化類
mtd = getattr(testModel , method);#調用testModel類中的get()方法。
mtd(obj);
如果要調用,可以直接使用M("auth","get");,相當於調用引入了模塊和類,並進行實例化,然后調用authModel.get()方法。
安裝第三方模塊
上面主要講的是自己寫模塊,但是實際上python作為一個”膠水語言“,很多功能已經被別人實現了,我們沒有必要自己重復的實現一部分,一定要有”拿來主義“
安裝第三方模塊,是通過包管理工具pip完成的。
注意在安裝python的時候,確保安裝時勾選了pip和Add python.exe to Path。
在命令提示符窗口下嘗試運行pip,如果Windows提示未找到命令,可以重新運行安裝程序添加pip。
注意:Mac或Linux上有可能並存Python 3.x和Python 2.x,因此對應的pip命令是pip3。
比如安裝excel處理工具xlrd。
pip install xlrd
但是pip源在國外(你懂的),所以下載會比較慢,可以使用國內的鏡像,比如豆瓣。
pip install -i http://pypi.douban.com/simple/ xlrd --trusted-host pypi.douban.com
模塊搜索路徑
當我們試圖加載一個模塊時,Python會在指定的路徑下搜索對應的.py文件,如果找不到,就會報錯
默認情況下,Python解釋器會搜索當前目錄、所有已安裝的內置模塊和第三方模塊,搜索路徑存放在sys模塊的path變量中,如果我們要添加自己的搜索目錄,有兩種方法
- 直接修改sys.path,添加要搜索的目錄:
>>> import sys
>>> sys.path.append('/Users/michael/my_py_scripts')
- 設置環境變量PYTHONPATH,該環境變量的內容會被自動添加到模塊搜索路徑中。設置方式與設置Path環境變量類似。注意只需要添加你自己的搜索路徑,Python自己本身的搜索路徑不受影響。
