1. 程式人生 > >Python Module和Package辨析

Python Module和Package辨析

.html 執行 i++ ide pretty ras 內容 color param

Python 基礎學習

說明

  • 這不是最基礎的新手教程,如需了解Python的數據類型、變量等基礎內容,請移步:https://docs.python.org/2/tutorial/index.html
  • 這裏的代碼使用Python2.7環境,沒有在>3版本號環境下測試,如有不兼容等問題,歡迎交流。郵箱:[email protected]

模塊(Moudule)和包(Package)辨析

  1. module
    通常模塊為一個文件,直接使用import來導入就好了。能夠作為module的文件類型有”.py”、”.pyo”、”.pyc”、”.pyd”、”.so”、”.dll”。

  2. package
    通常包總是一個文件夾,能夠使用import導入包,或者from + import來導入包中的部分模塊。

    包文件夾下為首的一個文件便是 init.py。然後是一些模塊文件和子文件夾,假如子文件夾中也有 init.py 那麽它就是這個包的子包了。

模塊的使用

以下演示module的使用。包括變量的引用、函數的引用和引用類型的引用。

模塊定義module_demo.py

# 變量
num = 37

#函數
def calc(a, b):
  return a + b

#類
class person:
  def speak(self):
    print "i am a person."
p = person()

模塊使用module_usage.py

import module_demo

print module_demo.num

print module_demo.calc(1, 2)

module_demo.p.speak()

執行結果

37
3
i am a person

到這裏,我們已經了解了模塊的引入和使用。那麽在現實中我們非常可能須要引入多個模塊,應該怎樣做呢?答案是用逗號分隔就能夠了。例如以下所看到的:

模塊使用module_usage.py

import module_demo, module_demo2
...

這裏值得補充的是,引入是能夠使用別名的,使用as關鍵字就能夠了。

模塊使用module_usage.py

import module_demo, module_demo2 as demo
...

假設我們僅僅希望引用模塊中的某個(些)對象呢,我們能夠單獨引入麽?答案是能夠的。使用例如以下:
模塊使用module_usage2.py

from module_demo import calc, p

print calc(1, 2)

p.speak()

從上面的案例中我們發現,我們引入多個對象時,僅僅須要逗號切割就好了。

這裏略微須要註意的是*的使用,比方我們使用from module_demo import *。我們會以為這是導入模塊中全部的對象。通常情況下確實如此,可是假設該模塊中定義了例如以下內容:

__all__ = [ ‘bar‘, ‘spam‘ ]     # 定義使用 `*` 能夠導入的對象

你就得小心註意了。這時候*僅僅代表all所定義的對象。其它的對象不會被導入。

敲黑板 關鍵問題來了,這個import能夠出如今代碼的不論什麽位置,那假設我們多次引入會發生什麽呢?模塊中的代碼*僅僅*在該模塊被首次導入時執行。

後面的import語句僅僅是簡單的創建一個到模塊名字空間的引用而已。

包的使用

多個關系密切的模塊應該組織成一個包,以便於維護和使用。

這項技術能有效避免名字空間沖突。創建一個名字為包名字的文件夾並在該文件夾下創建一個init.py 文件就定義了一個包。你能夠依據須要在該文件夾下存放資源文件、已編譯擴展及子包。

舉例來說,一個包可能有以下結構:

Graphics/
      __init__.py
      Primitive/
         __init__.py
         lines.py
         fill.py
         text.py
         ...
      Graph2d/
         __init__.py
         plot2d.py
         ...
      Graph3d/
         __init__.py
         plot3d.py
         ...
      Formats/
         __init__.py
         gif.py
         png.py
         tiff.py
         jpeg.py

import語句使用以下幾種方式導入包中的模塊:

import Graphics.Primitive.fill #導入模塊Graphics.Primitive.fill,僅僅能以全名訪問模塊屬性,比如 Graphics.Primitive.fill.floodfill(img,x,y,color).  
from Graphics.Primitive import fill# 導入模塊fill ,僅僅能以 fill.屬性名這樣的方式訪問模塊屬性,比如 fill.floodfill(img,x,y,color).  
from Graphics.Primitive.fill import floodfill #導入模塊fill ,並將函數floodfill放入當前名稱空間,直接訪問被導入的屬性,比如 floodfill(img,x,y,color). 

不管一個包的哪個部分被導入, 在文件init.py中的代碼都會執行.這個文件的內容同意為空,只是通常情況下它用來存放包的初始化代碼。導入過程遇到的全部 init.py文件都被執行.因此 import Graphics.Primitive.fill 語句會順序執行 Graphics 和 Primitive 文件夾下的init.py文件.

下邊這個語句具有歧義:

from Graphics.Primitive import * 

這個語句的原意圖是想將Graphics.Primitive包下的全部模塊導入到當前的名稱空間.然而,因為不同平臺間文件名稱規則不同(比方大寫和小寫敏感問題), Python不能正確判定哪些模塊要被導入.這個語句僅僅會順序執行 Graphics 和 Primitive 文件夾下的init.py文件. 要解決問題,應該在Primitive文件夾以下的init.py中定義一個名字all的列表,比如:

# Graphics/Primitive/__init__.py  
__all__ = ["lines","text","fill",...]  

這樣,上邊的語句就能夠導入列表中全部模塊.

以下這個語句僅僅會執行Graphics文件夾下的init.py文件,而不會導入不論什麽模塊:

import Graphics  
Graphics.Primitive.fill.floodfill(img,x,y,color)  # 失敗!  

只是既然 import Graphics 語句會執行 Graphics 文件夾下的 init..py文件,我們就能夠採取以下的手段來解決問題:

# Graphics/__init__.py  
import Primitive, Graph2d, Graph3d  
# Graphics/Primitive/__init__.py  
import lines, fill, text, ... 

這樣import Graphics語句就能夠導入全部的子模塊(僅僅能用全名來訪問這些模塊的屬性).

Python Module和Package辨析