Python 进阶_模块 amp; 包
目錄
- 目錄
- 模塊的搜索路徑和路徑搜索
- 搜索路徑
- 命名空間和變量作用域的比較
- 變量名的查找覆蓋
- 導(dǎo)入模塊
- import 語(yǔ)句
- from-import 語(yǔ)句
- 擴(kuò)展的 import 語(yǔ)句 as
- 自動(dòng)載入模塊
- 模塊導(dǎo)入的特性
- 模塊內(nèi)建函數(shù)
- __import__
- globals locals reload
- Package 包
- __init__py
- import package
模塊的搜索路徑和路徑搜索
搜索路徑
默認(rèn)的模塊搜索路徑在 Python 解析器編譯安裝時(shí)被指定, 我們可以通過(guò) sys 模塊來(lái)查看和修改它:
In [4]: sys.path Out[4]: ['','/usr/bin','/usr/lib/python2.7','/usr/lib/python2.7/plat-x86_64-linux-gnu','/usr/lib/python2.7/lib-tk','/usr/lib/python2.7/lib-old','/usr/lib/python2.7/lib-dynload','/usr/local/lib/python2.7/dist-packages','/opt/stack/keystone','/opt/stack/glance','/opt/stack/cinder','/opt/stack/nova','/opt/stack/horizon','/opt/stack/tempest','/opt/stack/oslo.vmware','/usr/lib/python2.7/dist-packages','/usr/lib/python2.7/dist-packages/IPython/extensions']存在于搜索路徑列表的路徑下的模塊就可以直接被 import 了.
我們還能夠通過(guò) sys.models 可以找到當(dāng)前導(dǎo)入了那些模塊和它來(lái)自薩滿路徑和地方.
NOTE: 這個(gè)路徑每個(gè)人都不盡相同, 在安裝 Openstack 項(xiàng)目時(shí), 每一個(gè)項(xiàng)目的根目錄都會(huì)加入到該目錄列表中
命名空間和變量作用域的比較
命名空間: 是變量名(標(biāo)識(shí)符)到實(shí)際對(duì)象的映射, 是一個(gè)字典. Python 的命名空間類型有 內(nèi)建命名空間/全局命名空間/嵌套命名空間/局部命名空間.
Python 解析器啟動(dòng)時(shí), 首先會(huì)加載 內(nèi)建命名空間 , 該空間的變量名映射被包含在 __builtin__ 模塊中, 我們可以通過(guò) __builtin__.__dict__ 來(lái)查看其包含的變量字典, 主要包含了 ERROR/內(nèi)建函數(shù) 等類型.
注意: __builtin__ 模塊和 __builtins__ 模塊的名稱非常相似, 在標(biāo)準(zhǔn)的 Python 環(huán)境中 __builtins__ 含有 __builtin__ 內(nèi)的所有變量名映射, 卻別在于 __builtins__ 是可以被修改的, 用于創(chuàng)建一個(gè) “沙盒” 環(huán)境, 但少有人用, 所以兩者并不相等.
作用域: 變量名有效的區(qū)域定義. 指定了一個(gè)變量名在一個(gè)指定的區(qū)域內(nèi)有效.
兩者的區(qū)別: 作用域和命名空間非常相似, 一個(gè)作用域的創(chuàng)建伴隨著新的命名空間的生成, 其一般是具有對(duì)應(yīng)的關(guān)系. 所以往往命名空間中含有的變量名在對(duì)應(yīng)的作用域中都是有效的. 但本質(zhì)的區(qū)別是: 命名空間是純粹意義上的變量名和對(duì)象的映射關(guān)系, 而作用域還指出了在代碼中的那個(gè)物理位置(模塊內(nèi)/類內(nèi)/函數(shù)類)可以訪問(wèn)到命名空間的變量名, 從而得到其映射的對(duì)象.
無(wú)限制的命名空間: Python 的一個(gè)特性在于我們可以動(dòng)態(tài)的為一個(gè)函數(shù)對(duì)象添加變量, 這種變量也稱之為實(shí)例屬性. 所以 Python 的命名空間是無(wú)限制的.
In [9]: def func():...: print "This is a func"...: In [10]: func.__dict__ Out[10]: {}In [13]: func.name = 'JMilkFan'In [14]: func.__dict__ Out[14]: {'name': 'JMilkFan'}變量名的查找/覆蓋
當(dāng)我們 call 一個(gè)變量名時(shí), Python 解析器的查找順序如下:
1. 先從局部命名空間開(kāi)始找, 如果找到了, 則引用變量名映射的對(duì)象. 若沒(méi)有找到, 則進(jìn)行下一步
2. 到嵌套命名空間找, 如果沒(méi)有找到, 則進(jìn)行下一步
3. 到全局命名空間找, 如果沒(méi)有找到, 則進(jìn)行下一步
4. 到內(nèi)置命名空間找, 如果沒(méi)有找到, 則進(jìn)入下一步
從這個(gè)變量名查找算法可以看出, 當(dāng)我們?cè)诖a物理位置定義了一個(gè)變量時(shí), 這個(gè)變量就會(huì)添加到命名空間中. 而且這個(gè)命名空間為變量名的查找提供了清單. 更重要的一點(diǎn)是這個(gè)查找算法還有效的覆蓋了外層作用域的同名變量. 局部作用域 覆蓋 嵌套作用域 覆蓋 全局作用域 覆蓋 內(nèi)置作用域.
導(dǎo)入模塊
import 語(yǔ)句
import module1[, module2, ..., moduleN]Python 允許一行導(dǎo)入多個(gè)模塊, 但那這并不符合 PEP8 的編程標(biāo)準(zhǔn), 所以建議使用多行導(dǎo)入的方式.
導(dǎo)入模塊類型的順序(中間已單空行隔開(kāi)):
1. Python 標(biāo)準(zhǔn)庫(kù)模塊
2. Python 第三方模塊
3. Python 自定義模塊
NOTE: 模塊的導(dǎo)入遵循作用域的原則, 在頂格導(dǎo)入的模塊, 那么模塊的作用域是全局的. 在函數(shù)或類內(nèi)導(dǎo)入的模塊, 其作用域就是局部或嵌套作用域.
from-import 語(yǔ)句
如果你希望從一個(gè)模塊中導(dǎo)入指定屬性, 或希望從一個(gè) package 中導(dǎo)入一個(gè)模塊, 都可以使用 form-import 語(yǔ)句.
from-import 語(yǔ)句也支持一行導(dǎo)入多個(gè)模塊或?qū)傩? EG.
from package import (module1, module2, module3, ..., moduleN)from-import 語(yǔ)句的好處在于: 針對(duì)性的導(dǎo)入可以提高效率和節(jié)省空間
NOTE: 我們一般建議導(dǎo)入到模塊即可, 非特殊情況不要導(dǎo)入包或模塊內(nèi)的屬性
擴(kuò)展的 import 語(yǔ)句 as
也稱之為別名, 模塊之間也會(huì)經(jīng)常出現(xiàn)同名的情況, 如果出現(xiàn)同一個(gè)模塊中導(dǎo)入了兩個(gè)或多個(gè)同名模塊的情況, 那么應(yīng)該為每個(gè)相同的模塊取一個(gè)別名來(lái)有效區(qū)分. 除此之外, 如果模塊的全稱過(guò)長(zhǎng), 我們也可以為其取一個(gè)短小的別名. EG.
import module1 as module_onefrom package import module1 as module_twoimport Tkinter as tk自動(dòng)載入模塊
Python 解析器在標(biāo)準(zhǔn)模式下啟動(dòng)會(huì)自動(dòng)的導(dǎo)入一個(gè)模塊, 例如 __bulitin__. 我們可以通過(guò) sys.modules 來(lái)查看已經(jīng)被導(dǎo)入到當(dāng)前環(huán)境下模塊字典, key 為模塊名, value 為模塊路徑.
import sys sys.modules.keys()模塊導(dǎo)入的特性
加載模塊時(shí)執(zhí)行文件
在導(dǎo)入模塊時(shí), 其頂格的代碼(全局變量/類定義/函數(shù)定義…)會(huì)被執(zhí)行, 所以不建議寫(xiě)太多的頂格代碼, 應(yīng)盡量多的將頂格代碼收入函數(shù)或類體內(nèi).導(dǎo)入和加載模塊是不一樣的
一個(gè)模塊可以被導(dǎo)入多次, 但正常情況下只能被加載一次. 當(dāng)然除了手動(dòng)加載之外. EG: 你需要在一個(gè)模塊中導(dǎo)入 5 個(gè)模塊, 其中之一為 sys 模塊, 然后另外的 4 個(gè)模塊也需要導(dǎo)入 sys 模塊, 這種情況下, sys 模塊只會(huì)被加載一次, 但卻會(huì)被導(dǎo)入 5 次.導(dǎo)入到當(dāng)前命名空間的變量
通過(guò) from-import 導(dǎo)入到當(dāng)前命名空間的模塊變量是不需要通過(guò)句點(diǎn)標(biāo)識(shí)符來(lái)調(diào)用的, 直接就可以引用. 但是不建議通過(guò) from-import 來(lái)直接導(dǎo)入模塊變量, 這樣容易污染當(dāng)前的命名空間, 可能導(dǎo)致覆蓋一個(gè)已經(jīng)存在的具有相同名字的對(duì)象.
模塊內(nèi)建函數(shù)
__import__()
格式:
__import__(module_name[, globals[, locals[, fromlist]]]) # globals 是全局命名空間的字典 ? globals() # locals 是局部命名空間的字典 ? locals() # fromlist 是 from-import 語(yǔ)句導(dǎo)入的變量名的列表 ? []當(dāng)我們執(zhí)行 import 語(yǔ)句的時(shí)候, 實(shí)際上是調(diào)用了 __import__() 內(nèi)置函數(shù), EG:
import sys # 等效于 sys = __import__('sys')globals() / locals() / reload()
- globals(): 返回調(diào)用者的全局命名空間的字典
locals(): 返回調(diào)用者的局部命名空間的字典
NOTE: 如果在全局命名空間調(diào)用上面兩個(gè)內(nèi)置函數(shù), 那么兩者返回的字典是相同的-
reload(): 重新導(dǎo)入一個(gè)已經(jīng)被導(dǎo)入了的模塊
NOTE: reload() 由兩個(gè)使用限制 - 模塊必須全部被導(dǎo)入, 不能重載通過(guò) from-import 來(lái)導(dǎo)入模塊屬性的模塊
- 該模塊必須是已經(jīng)被導(dǎo)入了的, 才能被重載
模塊的頂格代碼在導(dǎo)入的時(shí)候會(huì)執(zhí)行且僅執(zhí)行一次, 再次導(dǎo)入的時(shí)候不會(huì)被執(zhí)行, 如果希望再次執(zhí)行的話, 可以使用 reload()
Package 包
模塊是代碼的組織形式, 包是模塊的組織形式. 如果在一個(gè)目錄中創(chuàng)建了 __init__.py 文件, 那么 Python 解析器會(huì)將該目錄標(biāo)識(shí)為一個(gè)包 Package.
NOTE: 我們一般在使用 import 語(yǔ)句的時(shí)候, 建議導(dǎo)入到模塊級(jí)別, 不要導(dǎo)入模塊屬性, 也不要導(dǎo)入包.
__init__.py
__init__.py 文件是包的標(biāo)識(shí)文件, 作為包的初始化模塊, from-import 包下的模塊會(huì)子包時(shí), 需要用到該初始化模塊, 所以現(xiàn)在如果一個(gè)包中沒(méi)有該模塊時(shí), 會(huì)觸發(fā) ImportWarning 信息.
import package
如果我們不需要使用初始化模塊__init__.py時(shí). 該模塊的內(nèi)容為空, 如果我們需要使用該模塊時(shí), import packageName == import packageName._init_.
而且需要注意的是: 如果我們執(zhí)行 from package import * 時(shí), 會(huì)將該包下的所有模塊和屬性導(dǎo)入, 實(shí)際上這種做法是不科學(xué)的. 所以在包的初始化模塊文件中有一個(gè)特殊屬性 __all__ , __all__ 屬性由一個(gè)模塊名字組成的列表組成, 這個(gè)列表中包含了所有在執(zhí)行全導(dǎo)入時(shí)應(yīng)該被導(dǎo)入的模塊和屬性的名字.
總結(jié)
以上是生活随笔為你收集整理的Python 进阶_模块 amp; 包的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Node.js express 入门示例
- 下一篇: Swift和Objective-C混编注