Python模塊的顯要特性:屬性

模塊的顯要特性:屬性

導入和重載提供了一種自然的程序啓動的選擇,因爲導入操作將會在最後一步執行文件。從更宏觀的角度來看,模塊扮演了一個工具庫的角色,這將在第五部分學到。從一般意義上來說,模塊往往就是變量名的封裝,被認作是命名空間。在一個包中的變量名就是所謂的屬性:也就是說,屬性就是綁定在特定的對象上的變量名(就像一個
模塊)。

在典型的應用中,導入者得到了模塊文件中在頂層所定義的所有變量名。這些變量名通常被賦值給通過模塊函數、類、變量以及其他被導出的工具。這些往往都會在其他文件或程序中使用。表面上來看,一個模塊文件的變量名可以通過兩個Python語句讀取—— import和from,以及reload調用。

爲了講清楚,請使用文本編輯器創建一個名爲myfile.py的單行的Python模塊文件,其內容如下所示:

  1. title = "The Meaning of Life" 

這也許是世界上最簡單的Python模塊文件之一了(它只包含了一行賦值語句),但是它已經足夠講明白基本的要點。當文件導入時,它的代碼運行並生成了模塊的屬性。這個賦值語句創建了一個名爲title的模塊的屬性。

可以通過兩種不同的辦法從其他組件獲得這個模塊的title屬性。第一種,你可以通過使用一個import語句將模塊作爲一個整體載入,並使用模塊名後跟一個屬性名來獲取它:

  1. % python# Start Python  
  2. >>> import myfile# Run file; load module as a whole  
  3. >>> print(myfile.title)# Use its attribute names: '.' to qualify  
  4. The Meaning of Life 

一般來說,這裏的點號表達式代表了object.attribute的語法,可以從任何的object中取出其任意的屬性,並且這是Python代碼中的一個常用操作。在這裏,我們已經使用了它去獲取在模塊myfile中的一個字符串變量title,即myfile.title。

作爲替代方案,可以通過這樣的語句從模塊文件中獲得(實際上是複製)變量名:

  1. % python# Start Python  
  2. >>> from myfile import title# Run file; copy its names  
  3. >>> print(title)# Use name directly: no need to qualify  
  4. The Meaning of Life 

就像今後看到的更多細節一樣,from和import很相似,只不過增加了對載入組件的變量名的額外的賦值。從技術上講,from複製了模塊的屬性,以便屬性能夠成爲接收者的直接變量。因此,能夠直接以title(一個變量)引用導入字符串而不是myfile.title(一個屬性引用注3。

無論使用的是import還是from去執行導入操作,模塊文件myfile.py的語句都會執行,並且導入的組件(對應這裏是交互提示模式)在頂層文件中得到了變量名的讀取權。也許在這個簡單的例子中只有一個變量名(變量title被賦值給一個字符串),但是如果開始在模塊中定義對象,例如,函數和類時,這個概念將會很有用。這樣一些對象就變成了可重用的組件,可以通過變量名被一個或多個客戶端模塊讀取。

在實際應用中,模塊文件往往定義了一個以上的可被外部文件使用的變量名。下面這個例子中定義了三個變量名:

  1. a = 'dead'# Define three attributes  
  2. b = 'parrot'# Exported to other files  
  3. c = 'sketch' 
  4. print(a, b, c)# Also used in this file 

文件treenames.py,給三個變量賦值,並對外部世界生成了三個屬性。這個文件並且在一個print語句中使用它自有的三個變量,就像在將其作爲頂層文件運行時看到的結果一樣:

  1. % python threenames.py  
  2. dead parrot sketch 

所有的這個文件的代碼運行起來就和第一次從其他地方導入(無論是通過import或者from)後一樣。這個文件的客戶端通過import得到了具有屬性的模塊,而客戶端使用from時,則會獲得文件變量名的複本。

  1. % python  
  2. >>> import threenames# Grab the whole module  
  3. dead parrot sketch  
  4. >>> 
  5. >>> threenames.b, threenames.c  
  6. ('parrot', 'sketch')  
  7. >>> 
  8. >>> from threenames import a, b, c# Copy multiple names  
  9. >>> b, c  
  10. ('parrot', 'sketch') 

這裏的結果打印在括號中,因爲它們實際上是元組(本書的下一部分介紹的一種對象);目前我們可以暫時忽略它們。

一旦你開始就像這裏一樣在模塊文件編寫多個變量名,內置的dir函數開始發揮作用了。你可以使用它來獲得模塊內部的可用的變量名的列表。下面代碼返回了一個Python字符串列表(我們將從下一章開始學習列表):

  1. >>> dir(threenames)  
  2. ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'a', 'b', 'c'] 

我們在Python 3.0和Python 2.6中分別運行它,較早的Python可能返回較少的名字。當dir函數就像這個例子一樣,通過把導入模塊的名稱傳至括號裏,進行調用後,它將返回這個模塊內部的所有屬性。其中返回的一些變量名是“免費”獲得的:一些以雙下劃線開頭並結尾的變量名,這些通常都是由Python預定義的內置變量名,對於解釋器來說有特定的意義。那些通過代碼賦值而定義的變量(a、b和c)在dir結果的最後顯示。

模塊和命名空間

模塊導入是一種運行代碼文件的方法,但是就像稍後我們即將在本書中討論的那樣,模塊同樣是Python程序最大的程序結構。

一般來說,Python程序往往由多個模塊文件構成,通過import語句連接在一起。每個模塊文件是一個獨立完備的變量包,即一個命名空間。一個模塊文件不能看到其他文件定義的變量名,除非它顯式地導入了那個文件,所以模塊文件在代碼文件中起到了最小化命名衝突的作用。因爲每個文件都是一個獨立完備的命名空間,即使在它們拼寫相同的情況下,一個文件中的變量名是不會與另一個文件中的變量衝突的。

實際上,就像你將看到的那樣,正是由於模塊將變量封裝爲不同部分,Python具有了能夠避免命名衝突的優點。我們將會在本書後面章節討論模塊和其他的命名空間結構(包括類和函數的作用域)。就目前而言,模塊是一個不需要重複輸入而可以反覆運行代碼的方法。

注意:import VS from:我應該指出,from語句在某種意義上戰勝了模塊的名稱空間分隔的目的,因爲from把變量從一個文件複製到另一個文件,這可能導致在導入的文件中相同名稱的變量被覆蓋(並且,如果發生這種情況的話,不會爲你給出警告)。這根本上會導致名稱空間重疊到一起,至少在複製的變量上會重疊。

因此,有些人建議使用import而不是from。然而,我不建議這麼做,不僅因爲from更短,而且因爲它傳說中的問題在實際中幾乎不是問題。此外,這是由你來控制的問題,可以在from中列出想要的變量;只要你理解它們將是要賦的值,這不會比編寫賦值語句更危險,而賦值是你可能想要使用的另一功能。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章