Python 學習 第九篇:模塊

模塊是把程序代碼和數據封裝的Python文件,也就是說,每個以擴展名py結尾的Python源代碼文件都是一個模塊。每個模塊文件就是一個獨立的命名空間,用於封裝頂層變量名;在一個模塊文件的頂層定義的全部的變量名(函數名也是一個變量名),稱做模塊的屬性。導入模塊給予了對模塊的全局做用域中的變量名的讀取權,也就是說,在模塊導入時,模塊文件的全局做用域變成了模塊內對象的命名空間。app

導入一個模塊以後,可使用模塊中定義的屬性,例如,在模塊moduleA中導入一個模塊moduleB,那麼moduleB就變成了命名空間,在moduleA中可使用moduleB中的全局變量,引用的格式是:moduleB.attribution_name。編輯器

歸納來講,Python中的模塊擁有三個大的做用:函數

  • 代碼重用:模塊用於保存代碼,按照須要導入或從新導入模塊,以使用模塊中的代碼。
  • 變量封裝:模塊把變量名封裝起來,模塊變成了一個獨立的命名空間,模塊封裝的變量名變成了屬性,這就避免了變量名的衝突。
  • 代碼共享:把通用的代碼組織成模塊,分享給他人。

一,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語句和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是隱式的賦值語句:

  • import把整個模塊對象賦值給一個變量名,模塊文件的名稱就是變量名;
  • form把一個或多個變量名稱賦值給另外一個模塊中同名的變量名;以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()函數。

  • 導入(不管是經過import或from語句)只會在模塊第一次導入時,加載和執行模塊的代碼;
  • 以後的導入只會使用已加載的模塊對象,不會從新執行模塊的代碼;
  • imp.reload()函數在不停止Python程序的狀況下,強制Python從新加載和執行模塊的代碼。

 注意,在使用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__就會設置爲字符串"__main__"
  • 若是文件被導入,__name__就會設置模塊名

 模塊能夠檢測本身的__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會從頭至尾執行語句,也就是說,語句只會引用前面已經定義的變量,這就是變量的前向引用,所以,模塊頂層代碼的語句順序是很是重要的。

  • 在導入時,模塊文件頂層的代碼(不在函數內),在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

 

參考文檔:

相關文章
相關標籤/搜索