採用書籍Python核心編程(第二版),人民郵電出版社,2008年7月第1版。本書以Python2.5爲主,但筆記主要以Python3.6爲主。
第12章
模塊是用來組織Python代碼的方法,而包是用來組織模塊的
12.1 模塊和文件
- 代碼量變大—>把代碼分成有組織的代碼段,彼此能夠交互—>代碼可以共享,實現重用。那些自我包含並且有組織的代碼片段就是模塊(module),吧其他模塊加入到你的模塊中的操作叫做導入(import)
- 如果說模塊(module)是按照邏輯來組織Python代碼的方法,那麼文件便是物理層上組織模塊的方法。一個文件被看作一個獨立模塊,一個模塊也可以被看作是一個文件
- 模塊命名空間(也叫名稱空間,namespace):從名稱到對象的關係映射集合,模塊的屬性名稱均屬於該集合。每個模塊都定義了自己的唯一的名稱空間。
- 搜索路徑和路徑搜索:前者爲名詞,後者爲動詞。前者是一組預定義有用途的目錄,後者是查找某個文件的操作。默認搜索路徑是在安裝時指定的,可以用環境變量PYTHOINPATH或保存在sys模塊中的sys.path變量進行修改。
12.2 名稱空間
- 名稱空間是名稱(標識符)到對象的映射。向名稱中添加名稱的操作過程涉及綁定標識符到指定對象的操作(以及給對象的引用計數加1)。
- 在程序執行期間,有2個或3個活動的名稱空間:局部名稱空間、全局名稱空間和內建名稱空間。局部名稱空間會變化,可能有可能無,所以是“2個或3個”。
- Python解釋器會首先加載內建名稱空間。隨後加載全局名稱空間,它會在模塊開始執行後變爲活動名稱空間。如果在執行期間調用了一個函數,那麼將會創建除第三個名稱空間,即局部名稱空間。(Java中一對新的大括號會生成一個局部作用域,Python和其不同)
- 名稱空間和變量作用域:名稱空間是純粹意義上的名字和對象件的映射關係,而作用域還指出了在代碼中可以訪問這些名字的物理位置。
- 名字查找:訪問一個屬性時,按局部名稱空間—>全局名稱空間—>內建名稱空間的順序查找它的名字。若沒有找到,就會出現NameError;若局部和全局或內建有相同的名稱,訪問時會覆蓋。
- Python中一切皆對象。你可以在任何需要放置數據的地方獲得一個名稱空間。
12.3 導入模塊
- 導入語句:import module。
- 模塊在頂層導入,它的作用域就是全局的;在函數中導入,它的作用域是局部的。
- 如果模塊被第一次導入,它將被加載並執行。模塊的頂層代碼將直接被執行,包括全局變量和函數的聲明(函數本身並不會被執行,因爲沒有調用啊哈哈哈)。
- 一個模塊可被導入多次。,但只被加載和執行一次(就是第一次),這樣阻止了多重導入時代碼被多次執行。若用戶自定義模塊被修改需重新導入,需使用reload。
- from-import語句:把模塊中的屬性導入到當前的名稱空間,方便進行訪問;不可以修改該屬性,因爲修改相當於定義了一個新的同名的局部變量!
# 導入模塊推薦順序
import Python標準庫模塊
import Python第三方模塊
import 應用程序自定義模塊
# 導入模塊中的指定屬性 from-import
from module import name1, name2, ...
from module import * # 導入所有屬性,不推薦
# 擴展import語句的as,取別名,方便理解和記憶
import module as XXX
from module import name1 as XXX
import numpy as np
import pandas as pd
# 重新導入自定義模塊需要使用imp模塊中的reload方法
from imp import reload
reload(module)
12.4 模塊內建函數
系統爲模塊提供了一些功能上的支持。
# 1.__import__():實際上導入模塊的函數
var = __import__(module_name) # 參數爲字符串;返回值爲對應的模塊對象,所以需要將引用傳給變量,否則無法使用該模塊
sys = __import__('sys') # 等價於import sys
# 2.globals()和locals():返回調用者全局和局部名稱空間的字典的函數
# 在全局名稱下,globals()和locals()返回相同的字典,因爲此時的局部名稱空間就是全局空間
def foo():
print('calling foo()...')
num = 123
name = 'foo'
print("foo()'s globals:", globals().keys())
print("foo()'s locals:", locals().keys())
print("__main__()'s globals:", globals().keys())
print("__main__()'s locals:", locals().keys())
foo()
# 3.reload():重新導入模塊需要使用imp模塊中的reload方法
# 模塊必須是全部導入(不是from-import),reload()函數的參數必須是模塊自身而不是模塊名字的字符串,reload()函數重新導入導致模塊會執行
from imp import reload
reload(module)
12.5 包
包是一個有層次的文件目錄結構,它定義了一個由模塊和子包組成的Python應用程序執行環境。Python1.5加入了包,用來幫助解決如下問題:
- 爲平坦的名稱空間加入有層次的組織結構
- 允許程序員把有聯繫的模塊組合到一起
- 允許分發這使用目錄結構而不是一大堆混亂的文件
- 幫助解決有衝突的模塊名稱
# 1.目錄結構
# 導入包中的模塊:from package.module import sub_module
# 模塊下的__init__.py 文件,用於初始化模塊。
# 2.使用from-import導入包:
# from package import * # 導入package.module下的所有模塊(__all__變量中定義的)
# __init__.py 中的 __all__ 變量包含執行該語句時應該導入的模塊名字符串列表。
# 3.絕對導入
# 所有的導入都被認爲是絕對的,即這些被導入的模塊必須通過Python路徑(sys.path或是PYTHONPATH)來訪問。
# 4.相對導入
from Phone.Mobile.Analog import dial # 絕對導入
from .Analog import dial # 相對導入
from ..Fax import G3.dial # 相對導入
12.6 模塊的其他特性
- Python解釋器在標準模式下啓動時,一些模塊會被解釋器自動導入,用於系統相關操作。sys.modules變量包含一個由當前載入(完整且成功導入)到解釋器的模塊組成字典,模塊名爲鍵,對應的位置爲值。
- 阻止屬性導入。如果不想讓某個模塊屬性被 from module import * 導入 ,可以在不想導入的屬性名稱加上一個下劃線_。
- 不區分大小的導入。指定 PYTHONCASEOK 環境變量,以不區分大小寫地導入模塊。
12.7 相關模塊
- imp:這個模塊提供了一些底層的導入者功能。
- modulefinder:該模塊允許你查找 Python 腳本所使用的所有模塊。
- pkgutil:該模塊提供了多種把 Python 包打包爲一個”包”文件(*.pkg)分發的方法。
- site:和 *.pth文件配合使用, 指定包加入 Python 路徑的順序。
- zipimport :使用該模塊導入 ZIP 歸檔文件中的模塊。
- distutils:該模塊提供了對建立、 安裝、分發 Python 模塊和包的支持。
參考資料: