Python模塊與包

模塊

模塊是很是簡單的Python文件,單個Python文件就是一個模塊,兩個文件就是兩個模塊。python

import語句是用來導入模塊或者從模塊裏導入特定的類或者函數。如前面咱們用過的math模塊,從而可使用sqrt函數來計算距離。程序員

假若有一個包含Database類的database.py的模塊。現有另外一個模塊爲product.py,它須要從database.py裏實例化一個Database類,而後就能夠在數據庫中執行相關產品查詢。數據庫

import database
db = database.Database()
#數據庫搜索操做

這時任何在database這個模塊裏面的類或者函數,均可以經過database.<something>這種激發訪問。或者,也能夠用from ... import語法來導入一個類。編程

from database import Database
db = Database()

也能夠將導入的類進行重命名編程語言

from database import Database as DB  # 重命名
db = DB()

也能夠在一行裏面導入多項,好比database還含有Query類函數

from database import Database, Query

可是,不少教程與經驗建議不要導入模塊裏面全部的類,以下的寫法是不採用的。測試

from database import * 

組織模塊

一個包(package)就是放在一個文件夾裏的模塊集合。包的名字就是文件夾的名字。咱們須要作的是告訴python這個文件夾是一個包,並且把一個名爲__init__.py的文件(一般是空的)放在這個文件夾裏。若是咱們忘記建立這個文件夾,就無法從這個文件夾裏面導入那些模塊。spa

例如在咱們的工做目錄裏,把咱們的模塊放在了一個叫ecommerce(電子商務)的包裏,這個目錄一樣包含一個main.py的文件用來啓動程序。在ecommerce包裏再添加一個payments的包用來管理不一樣的付款方式,文件夾的層次結構以下所示:code

parent_directory/
    main.py
    ecommerce/
        __init__.py
        database.py
        products.py
        payments/
            __init__.py
            paypal.py
            authorizenet.py

其中producs.py的有Product類對象

class Product:
    pass

database.py有Database類

class Database:
    pass

模塊的導入方式有兩種:絕對導入和相對導入。

絕對導入

要先給出這個模塊、函數的完整路徑,如在main.py須要訪問produces模塊中的Product類,使用使用以下的方法進行絕對導入:

import ecommerce.products
product = ecommerce.products.Product()

或者(我的比較喜歡這種方式):

from ecommerce.products import Product
product = Product()

或者:

from ecommerce import products
product = products.Product()

import語句使用點號做爲分隔符來分隔包或者模塊

上述的均可以使用,若是要導入一個模塊中的不少類,使用使用第三種方法,若是是指導入一個模塊的一兩個類,則可使用第二種方法具體指明。

相對導入

在包(package)的狀況下,若是知道父模塊的名稱,那麼就可使用相對導入。好比當前在products模塊下工做,想從隔壁的database模塊導入Database類,就可使用相對導入:

from .database import Database   # 點號表示使用當前路徑的database模塊

若是咱們正在編輯ecommerce.payments包裏的paypal模塊,須要引用父包裏的database模塊:

from ..database import Database  # 使用兩個點號表示訪問上層的父類

若是ecommerce有contact包,該包裏有email模塊,須要將該模塊的sendEmail函數導入到paypal模塊中,

from ..contact.email import sendEmail   

 數據訪問權限

大部分的面向對象的編程語言都有一個「訪問控制」的概念,好比私有的(private)、受保護的(protected)和公共的(public)。但python並無這種強制規定。在技術層面上,一個類裏的全部方法和屬性都是公共可訪問的,如下有三種形式建議不一樣的訪問形式:

一、使用註釋進行提示建議。如能夠在docstring裏面放一個提示來代表這個方法只是內部使用的

二、給某個屬性或者方法加一個下劃線的前綴,大部分python程序員會把這個解釋爲「這是個內部變量,使用以前要三思」

三、給某個屬性或者方法添加一個雙下劃線的前綴,強烈建議爲內部變量。訪問時須要名稱改編(name mangling),即在該方法或者屬性前面自動加一個_<classname>的前綴(單下劃線)。

通常狀況下,不會使用加下劃線或者雙下劃線的變量。

class SecretString:
    ''' A not-at-all secure way to store a secret string'''

    def __init__(self, plain_string, pass_phrase):
        self.__plain_string = plain_string
        self.__pass_phrase = pass_phrase 

    def decrypt(self, pass_phrase):
        ''' Only show the string if the pass_phrase is correct.'''
        if pass_phrase == self.__pass_phrase:
            return self.__plain_string
        else:
            return 

將上述代碼存儲爲filename.py,而後使用python -i filename.py執行這個腳本,而後在交互的解釋器裏進行以下的測試:

>>> secret_string = SecretString("ACME: Top Secret", "antwerp")
>>> print(secret_string.decrypt("antwerp"))
ACME: Top Secret
>>> print(secret_string.__plain_text)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'SecretString' object has no attribute '__plain_text'
>>> print(secret_string._SecretString__plain_string)
ACME: Top Secret

從包裏直接導入變量

在ecommerce包裏有兩個模塊,一個是database.py,另外一個是products.py,假設database裏面有一個db變量,這個變量在不少地方都會被訪問,那麼咱們下面的代碼將能夠實現用import ecommerce.db取代import ecommerce.database.db。

經過在__init__.py文件(定義目錄爲包),在這裏文件中能夠包含任意變量或者類的生命,並且它會做爲這個包的一部分被咱們使用。在這個例子中,若是有ecommerce/__init__.py文件裏包含這麼一行:

from .database import db

那麼咱們就能夠用下面的語句,在mian.py或者其餘文件訪問這個db屬性了:

from ecommerce import db

以上主要在於致使ecommerce.py這個文件是一個模塊而不是包的緣由在於__init__.py。

若是你把全部代碼放在了一個單獨的模塊,以後又決定拆成一個包裏的多個包,__init__.py文件一樣對你有幫忙。

其餘模塊若是想要訪問這個新包,__init__.py文件仍然是主要的切入點。可是在內部,代碼仍然能夠被組織成許多不一樣模塊或者子包。

 

參考:

一、《Python3 面向對象編程》 [加]Dusty Philips 著

相關文章
相關標籤/搜索