天天看點

Python 進階_子產品 & 包目錄子產品的搜尋路徑和路徑搜尋命名空間和變量作用域的比較變量名的查找/覆寫導入子產品子產品導入的特性子產品内建函數Package 包

<a href="#%E7%9B%AE%E5%BD%95">目錄</a>

<a href="#%E6%A8%A1%E5%9D%97%E7%9A%84%E6%90%9C%E7%B4%A2%E8%B7%AF%E5%BE%84%E5%92%8C%E8%B7%AF%E5%BE%84%E6%90%9C%E7%B4%A2">子產品的搜尋路徑和路徑搜尋</a>

<a href="#%E6%90%9C%E7%B4%A2%E8%B7%AF%E5%BE%84">搜尋路徑</a>

<a href="#%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E5%92%8C%E5%8F%98%E9%87%8F%E4%BD%9C%E7%94%A8%E5%9F%9F%E7%9A%84%E6%AF%94%E8%BE%83">命名空間和變量作用域的比較</a>

<a href="#%E5%8F%98%E9%87%8F%E5%90%8D%E7%9A%84%E6%9F%A5%E6%89%BE%E8%A6%86%E7%9B%96">變量名的查找覆寫</a>

<a href="#%E5%AF%BC%E5%85%A5%E6%A8%A1%E5%9D%97">導入子產品</a>

<a href="#import-%E8%AF%AD%E5%8F%A5">import 語句</a>

<a href="#from-import-%E8%AF%AD%E5%8F%A5">from-import 語句</a>

<a href="#%E6%89%A9%E5%B1%95%E7%9A%84-import-%E8%AF%AD%E5%8F%A5-as">擴充的 import 語句 as</a>

<a href="#%E8%87%AA%E5%8A%A8%E8%BD%BD%E5%85%A5%E6%A8%A1%E5%9D%97">自動載入子產品</a>

<a href="#%E6%A8%A1%E5%9D%97%E5%AF%BC%E5%85%A5%E7%9A%84%E7%89%B9%E6%80%A7">子產品導入的特性</a>

<a href="#%E6%A8%A1%E5%9D%97%E5%86%85%E5%BB%BA%E5%87%BD%E6%95%B0">子產品内建函數</a>

<a href="#import">__import__</a>

<a href="#globals-locals-reload">globals locals reload</a>

<a href="#package-%E5%8C%85">Package 包</a>

<a href="#initpy">__init__py</a>

<a href="#import-package">import package</a>

預設的子產品搜尋路徑在 Python 解析器編譯安裝時被指定, 我們可以通過 sys 子產品來檢視和修改它:

存在于搜尋路徑清單的路徑下的子產品就可以直接被 import 了.

我們還能夠通過 sys.models 可以找到目前導入了那些子產品和它來自薩滿路徑和地方.

NOTE: 這個路徑每個人都不盡相同, 在安裝 Openstack 項目時, 每一個項目的根目錄都會加入到該目錄清單中

命名空間: 是變量名(辨別符)到實際對象的映射, 是一個字典. Python 的命名空間類型有 内建命名空間/全局命名空間/嵌套命名空間/局部命名空間.

Python 解析器啟動時, 首先會加載 内建命名空間 , 該空間的變量名映射被包含在 <code>__builtin__</code> 子產品中, 我們可以通過 <code>__builtin__.__dict__</code> 來檢視其包含的變量字典, 主要包含了 ERROR/内建函數 等類型.

注意: <code>__builtin__</code> 子產品和 <code>__builtins__</code> 子產品的名稱非常相似, 在标準的 Python 環境中 <code>__builtins__</code> 含有 <code>__builtin__</code> 内的所有變量名映射, 卻别在于 <code>__builtins__</code> 是可以被修改的, 用于建立一個 “沙盒” 環境, 但少有人用, 是以兩者并不相等.

作用域: 變量名有效的區域定義. 指定了一個變量名在一個指定的區域内有效.

兩者的差別: 作用域和命名空間非常相似, 一個作用域的建立伴随着新的命名空間的生成, 其一般是具有對應的關系. 是以往往命名空間中含有的變量名在對應的作用域中都是有效的. 但本質的差別是: 命名空間是純粹意義上的變量名和對象的映射關系, 而作用域還指出了在代碼中的那個實體位置(子產品内/類内/函數類)可以通路到命名空間的變量名, 進而得到其映射的對象.

無限制的命名空間: Python 的一個特性在于我們可以動态的為一個函數對象添加變量, 這種變量也稱之為執行個體屬性. 是以 Python 的命名空間是無限制的.

當我們 call 一個變量名時, Python 解析器的查找順序如下:

1. 先從局部命名空間開始找, 如果找到了, 則引用變量名映射的對象. 若沒有找到, 則進行下一步

2. 到嵌套命名空間找, 如果沒有找到, 則進行下一步

3. 到全局命名空間找, 如果沒有找到, 則進行下一步

4. 到内置命名空間找, 如果沒有找到, 則進入下一步

從這個變量名查找算法可以看出, 當我們在代碼實體位置定義了一個變量時, 這個變量就會添加到命名空間中. 而且這個命名空間為變量名的查找提供了清單. 更重要的一點是這個查找算法還有效的覆寫了外層作用域的同名變量. 局部作用域 覆寫 嵌套作用域 覆寫 全局作用域 覆寫 内置作用域.

Python 允許一行導入多個子產品, 但那這并不符合 PEP8 的程式設計标準, 是以建議使用多行導入的方式.

導入子產品類型的順序(中間已單空行隔開):

1. Python 标準庫子產品

2. Python 第三方子產品

3. Python 自定義子產品

NOTE: 子產品的導入遵循作用域的原則, 在頂格導入的子產品, 那麼子產品的作用域是全局的. 在函數或類内導入的子產品, 其作用域就是局部或嵌套作用域.

如果你希望從一個子產品中導入指定屬性, 或希望從一個 package 中導入一個子產品, 都可以使用 form-import 語句.

from-import 語句也支援一行導入多個子產品或屬性, EG.

from-import 語句的好處在于: 針對性的導入可以提高效率和節省空間

NOTE: 我們一般建議導入到子產品即可, 非特殊情況不要導入包或子產品内的屬性

也稱之為别名, 子產品之間也會經常出現同名的情況, 如果出現同一個子產品中導入了兩個或多個同名子產品的情況, 那麼應該為每個相同的子產品取一個别名來有效區分. 除此之外, 如果子產品的全稱過長, 我們也可以為其取一個短小的别名. EG.

Python 解析器在标準模式下啟動會自動的導入一個子產品, 例如 __bulitin__. 我們可以通過 sys.modules 來檢視已經被導入到目前環境下子產品字典, key 為子產品名, value 為子產品路徑.

加載子產品時執行檔案

在導入子產品時, 其頂格的代碼(全局變量/類定義/函數定義…)會被執行, 是以不建議寫太多的頂格代碼, 應盡量多的将頂格代碼收入函數或類體内.

導入和加載子產品是不一樣的

一個子產品可以被導入多次, 但正常情況下隻能被加載一次. 當然除了手動加載之外. EG: 你需要在一個子產品中導入 5 個子產品, 其中之一為 sys 子產品, 然後另外的 4 個子產品也需要導入 sys 子產品, 這種情況下, sys 子產品隻會被加載一次, 但卻會被導入 5 次.

導入到目前命名空間的變量

通過 from-import 導入到目前命名空間的子產品變量是不需要通過句點辨別符來調用的, 直接就可以引用. 但是不建議通過 from-import 來直接導入子產品變量, 這樣容易污染目前的命名空間, 可能導緻覆寫一個已經存在的具有相同名字的對象.

格式:

當我們執行 import 語句的時候, 實際上是調用了 <code>__import__()</code> 内置函數, EG:

globals(): 傳回調用者的全局命名空間的字典

locals(): 傳回調用者的局部命名空間的字典

NOTE: 如果在全局命名空間調用上面兩個内置函數, 那麼兩者傳回的字典是相同的

reload(): 重新導入一個已經被導入了的子產品

NOTE: reload() 由兩個使用限制

子產品必須全部被導入, 不能重載通過 from-import 來導入子產品屬性的子產品

該子產品必須是已經被導入了的, 才能被重載

子產品的頂格代碼在導入的時候會執行且僅執行一次, 再次導入的時候不會被執行, 如果希望再次執行的話, 可以使用 reload()

子產品是代碼的組織形式, 包是子產品的組織形式. 如果在一個目錄中建立了 <code>__init__.py</code> 檔案, 那麼 Python 解析器會将該目錄辨別為一個包 Package.

NOTE: 我們一般在使用 import 語句的時候, 建議導入到子產品級别, 不要導入子產品屬性, 也不要導入包.

__init__.py 檔案是包的辨別檔案, 作為包的初始化子產品, from-import 包下的子產品會子包時, 需要用到該初始化子產品, 是以現在如果一個包中沒有該子產品時, 會觸發 ImportWarning 資訊.

如果我們不需要使用初始化子產品<code>__init__.py</code>時. 該子產品的内容為空, 如果我們需要使用該子產品時, import packageName == import packageName._init_.

而且需要注意的是: 如果我們執行 <code>from package import *</code> 時, 會将該包下的所有子產品和屬性導入, 實際上這種做法是不科學的. 是以在包的初始化子產品檔案中有一個特殊屬性 <code>__all__</code> , <code>__all__</code> 屬性由一個子產品名字組成的清單組成, 這個清單中包含了所有在執行全導入時應該被導入的子產品和屬性的名字.