模塊是把程序代碼和數據封裝的Python文件,也就是說,每個以擴展名py結尾的Python源代碼文件都是一個模塊。每個模塊文件就是一個獨立的命名空間,用於封裝頂層變量名;在一個模塊文件的頂層定義的全部的變量名(函數名也是一個變量名),稱做模塊的屬性。導入模塊給予了對模塊的全局做用域中的變量名的讀取權,也就是說,在模塊導入時,模塊文件的全局做用域變成了模塊內對象的命名空間。app
導入一個模塊以後,可使用模塊中定義的屬性,例如,在模塊moduleA中導入一個模塊moduleB,那麼moduleB就變成了命名空間,在moduleA中可使用moduleB中的全局變量,引用的格式是:moduleB.attribution_name。編輯器
歸納來講,Python中的模塊擁有三個大的做用:函數
通常來講,一個Python程序結構是由一個主文件(又稱爲頂層文件、腳本)和多個模塊構成的,其中主文件包含了程序的控制流程,也就是啓動以後可以運行整個程序的文件,而模塊文件是用於提供工具的庫。工具
在Python中,一個文件導入了一個模塊來得到該模塊內定義的工具的訪問權,所以,通用的Python程序的結構就是:在頂層文件中導入模塊,並引用模塊中的工具。spa
例如,在腳本文件main.py中導入functools模塊中的reduce()函數,使用該工具函數實現列表元素的加和:命令行
from functools import reduce a=reduce((lambda x,y:x+y),range(0,5)) print(a)
定義模塊,只須要使用文本編輯器,把一些Python代碼輸入到文本文件中,而後以".py"爲擴展名名進行保存,任何此類文件都會被自動認爲是Python模塊。在模塊頂層指定的變量名是模塊的屬性。注意:模塊的文件名必須以擴展名 .py 結尾。code
例如,建立一個strtools模塊,文件名必須是strtools.py,文件的內容是Python代碼,其中append_suffix是模塊的屬性名,引用該屬性的格式是:strtools.append_suffix(arg):orm
def append_suffix(str): return str+'- py'
導入從本質上來說,就是爲了載入另外一個文件,並可以讀取該文件的內容。模塊的導入是由兩個語句來處理:對象
import語句和from語句都會加載模塊,加載的過程包括搜索、編譯和執行模塊文件。二者的差異在於:import語句 會讀取整個模塊,因此必須進行定義後才能讀取它的屬性;form語句直接獲取模塊中特定的變量名。blog
在一個導入語句中的模塊名起到兩個做用:識別加載的外部文件;把模塊名做爲命名空間,用於封裝模塊內的頂層變量名。在導入模塊時,模塊定義的對象也會在import語句執行時建立,經過module_name.attribution_name來引用模塊內定義的變量名。
例如,在主文件中導入strtools模塊,並使用append_suffix()函數:
import strtools mystr=strtools.append_suffix('It is a cat') print(mystr)
1,import語句
import語句使用一個變量名來引用整個模塊對象,所以,必須經過模塊名稱來得到模塊的屬性:
import strtools strool.append_suffix('xx')
2,from語句
from語句把變量名複製到另外一個做用域,所以,能夠直接在腳本中使用變量名,而不須要經過模塊:
from strtools import append_suffix append_suffix('xx')
因爲模塊中的變量名可能由不少,可使用*,取得模塊頂層的全部變量名,把模塊頂層的變量名都複製到當前的做用域內:
from strtools import *
從技術上來講,import和from * 語句都會使用相同的導入操做,from * 形式只是多加了步驟,把模塊中全部的屬性名複製到了導入的做用域以內。
3,導入只發生依次
模塊會在第一次import或from時載入並執行,而且只在第一次如此。默認狀況下,Python只對每一個文件作一次導入操做,以後的導入操做操做都只是取出已加載的模塊對象。
4,import和from是賦值語句
import和from是可執行的語句,而不是聲明語句,也就是說,被導入的模塊和變量名,直到它們所對應的import或from語句執行後,纔可使用。
import和from是隱式的賦值語句:
以from語句複製而來的變量名和其來源的文件之間沒有聯繫,爲了實際修改另外一個文件中的全局變量名,必須使用import語句。
例如,使用from導入變量x,修改變量不會影響模塊中x的值,這是由於from語句把模塊的對象複製到本地做用域的變量,因此,本地做用域對變量從新賦值,會建立一個新的對象。
from module import x,y x=1 # change the variable
可是,對可變類型對象的修改,會影響模塊的對象的值,這是由於list_names支持原處修改,這跟賦值不一樣:
from module import list_names list_names[0]='vic'
5,import和from的對等性
from只是把變量名從一個模塊複製到另外一個模塊,並不會對模塊名自己進行賦值。
從概念上來說,一個像這樣的from語句:
from module import name1,name2
與下面這些語句是等效的:
import module name1=module.name1 name2=module.name2 del module
就像全部的賦值語句,from語句會在導入者中建立新變量,而這些變量初始化時引用了被導入文件中的同名對象。不過,只有同名的變量名(並非全部的變量名)被賦值出來,而非模塊自己,from未指定的變量名都沒有複製出來。
從上文可知,模塊是變量名的封裝。Python會把每個.py文件看做一個模塊,建立模塊對象,以包含模塊內所複製的全部頂層變量名,這些頂層變量名就是模塊對象的屬性。
1,模塊語句會在首次導入時執行
模塊在第一次導入時,Python都會創建空的模塊對象,按照文件從頭至尾的順序,逐一執行模塊內的語句。
2,頂層的賦值語句會建立爲模塊屬性
在導入時,在模塊頂層的賦值語句左側的變量,成爲模塊對象的屬性,賦值的變量名會存在模塊的命名空間內。
3,模塊的命名空間可以經過屬性__dict__或dir(module)函數獲取
在導入時,Python會把創建模塊的命名空間的字典,經過模塊對象的屬性__dict__來讀取,也能夠經過dir(module)函數來讀取。
4,模塊是一個獨立的做用域
模塊內的命名空間是一個獨立的做用域,經過點號 ( . )來引用屬性,引用的格式是:object.attr_name。
從上文可知,導入只發生一次,要想重載模塊,須要 調用 reload()函數。
注意,在使用reload()函數重載模塊以前,模塊必定是已經預先導入了。
通常的用法是:導入一個模塊,在文本編輯器中修改其源代碼,而後將其重載。
import module ... use module.attributes ... # now, go change the module file from imp import reload reload(module) # get the changes ... use module.attributes
當調用reload()函數時,Python會從新讀取模塊問價的源代碼,從新執行其頂層代碼,在適當的地方修改已導入的模塊對象,reload()不會刪除並重建模塊對象。
在調用reload()函數以後,程序中任何引用該模塊的對象,自動會受到重載的影響。
1,重載模塊會致使模塊代碼的從新執行
reload()函數會使模塊從新執行模塊文件的新代碼,從新執行模塊文件的代碼,會覆蓋現有的命名空間,但不是把模塊對象刪除並進行重建。
2,模塊文件中頂層的賦值語句會使得變量名從新賦值
在調用reload()函數時,賦值語句會從新執行,進而模塊的頂層變量會被從新賦值,這會致使頂層變量引用的對象會從新建立。
例如,模塊重載會致使頂層的def語句從新執行,對函數名進行從新賦值,這使得函數對象會被從新建立,函數名引用的對象不是模塊以前的版本。
3,重載對import語句的影響
模塊重載會影響全部使用import語句讀取了模塊的腳本,這是由於使用import語句的腳本,須要經過點號運算獲取屬性,在模塊重載後,模塊的屬性變成了新值。
4,重載對from語句的影響
模塊重載只會對之後使用from語句的腳本形成影響,以前使用from語句來讀取屬性的變量名不會受到重載的影響,其引用的是值依然是重載以前所獲取的對象。
這是由於,模塊重載會致使模塊頂層變量的從新賦值,這使得模塊頂層變量引用的對象會從新建立,模塊頂層變量引用的是新對象,而在重載以前執行的from語句,變量引用的是舊版本的對象,這個舊版本的對象不會被銷燬,但和重載以後的新對象不是同一個對象了。
5,重載不會傳遞到導入的模塊
重載不會影響模塊已經導入的模塊,例如,若是要重載模塊A,而且模塊A導入模塊B和C,那麼重載只適用於A,而不適用於B和C。在重載模塊A時,模塊B和C因爲已經加載了,模塊A只會獲取已經載入的模塊B和C對象。
若是要重載已經導入的模塊,那麼必須顯式重載這些模塊:
from imp import reload # firstly reload imported modules reload(C) reload(B) # then reload the outer module reload(A)
在這一節中,咱們探索模塊的使用標誌,模塊內變量的前向引用,和點號運算符的特性等。
1,使用模式的標誌
每一個模塊都有個名爲__name__的內置屬性,Python會自動設置該屬性:
模塊能夠檢測本身的__name__屬性,以肯定本身是在執行(run)仍是導入(import)。
2,命令行參數
在Python中,sys.argv列表包含了命令行參數,它是反映在命令行上錄入的單詞的一個字符串列表,其中,第一項老是將要運行的腳本的名稱。
import sys
3,import語句和from語句的as擴展
import語句使用as擴展,能夠爲模塊設置別名:
from module import attr_long_name as short_name
from語句把從模塊導入的變量名,複製給腳本中的不一樣的變量名,當模塊中的變量名和當前做用域的變量名重名時,使用as擴展,能夠避免變量名衝突:
import module_long_name as short_name
4,前向引用
當模塊收入導入(或重載)時,Python會從頭至尾執行語句,也就是說,語句只會引用前面已經定義的變量,這就是變量的前向引用,所以,模塊頂層代碼的語句順序是很是重要的。
通常來講,前向引用只對當即執行的模塊頂層代碼有影響,函數能夠引用任意一個模塊頂層的變量名。
5,from是變量名的賦值,而import是引用對象
其實,from語句是一個普通的賦值運算,把模塊內的變量名賦值給導入者的做用域內的變量名,實際上就是把變量名賦值給變量名,兩個不一樣做用域內的變量共享對象的引用,也就是說,一個對象的引用位於不一樣的文件中。
例如,有模塊mod_1,有兩個屬性,變量x和函數printer:
x=1 def printer():print(x)
在文件mod_2中,使用from導入模塊mod_1,對變量x進行賦值,會致使變量x引用新的對象,而不是修改mod_1.py中的變量x的值:
from mod_1 import x, printer x=2 printer() # print 1
在文件mod_3中,使用import導入整個模塊,當使用點號運算符修改模塊內的屬性時,就會修改mod_1.py中的變量的值,點號運算符把Python定向到了模塊內的變量名,對變量進行修改,而不是賦值:
import mod_1 as m m.x=2 printer() # print 2
注意:點號運算符是引用變量,並修改變量的值。
6,reload()函數不會影響from導入
由於from語句在執行時會賦值變量名,因此,不會連接到變量名所在的模塊。經過from語句導入的變量名就簡單地變成了對象的引用。
當重載模塊時,模塊會從新建立對象,變量名引用新建的對象,然而位於重載以前的from引用的原始對象並不會改變,重載會影響後面的from語句。
from module import x ... from imp import reload() reload(module) #changes module in-place x #still references old object
reload()函數會影響import語句,這是由於,重載不會刪除和新建模塊對象,也就是說,import語句引用的模塊對象不變,可是,模塊對象中的屬性會被刪除重建。當經過點號來引用模塊的對象時,object.attr 會引用模塊的最新建立的變量。
import module ... from imp import reload() reload(module) #changes module in-place module.x #get current x: reflects module reloads
參考文檔: