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的文件(通常是空的)放在這個文件夾里。如果我們忘記創建這個文件夾,就沒法從這個文件夾里面導入那些模塊。

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

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並沒有這種強制規定。在技術層面上,一個類里的所有方法和屬性都是公共可訪問的,以下有三種形式建議不同的訪問形式:

1、使用注釋進行提示建議。如可以在docstring里面放一個提示來表明這個方法只是內部使用的

2、給某個屬性或者方法加一個下划線的前綴,大部分python程序員會把這個解釋為“這是個內部變量,使用之前要三思”

3、給某個屬性或者方法添加一個雙下划線的前綴,強烈建議為內部變量。訪問時需要名稱改編(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文件仍然是主要的切入點。但是在內部,代碼仍然可以被組織成許多不同模塊或者子包。

 

參考:

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM