2018年6月6日 星期三

[ Python 文章收集 ] Python __init__.py 作用詳解

Source From Here 
Preface 
__init__.py 文件的作用是將文件夾變為一個Python模塊,Python 中的每個模塊的包中,都有 __init__.py 文件。通常 __init__.py 文件為空,但是我們還可以為它增加其他的功能。我們在導入一個包時,實際上是導入了它的 __init__.py 文件。這樣我們可以在 __init__.py 文件中批量導入我們所需要的模塊,而不再需要一個一個的導入。 
  1. # mt/__init__.py  
  2. # __init__.py  
  3. import re  
  4. import urllib  
  5. import sys  
  6. import os  
  7.   
  8. # mt/a.py  
  9. import mt   
  10. print(mt.re, mt.urllib, mt.sys, mt.os)  
注意這裡訪問 __init__.py 文件中的引用文件,需要加上 "mt"。__init__.py 中還有一個重要的變量,__all__, 它用來將模塊全部導入: 
  1. # mt/__init__.py  
  2. __all__ = ['os''sys''re''urllib']  
  3.   
  4. # mt/a.py  
  5. from package import *  
這時就會把註冊在 __init__.py 文件中 __all__ 列表中的模塊和包導入到當前文件中來。可以了解到,__init__.py 主要控制包的導入行為。要想清楚理解 __init__.py 文件的作用,還需要詳細了解一下 import 語句引用機制. 可以被 import 語句導入的對像是以下類型: 
* 模塊文件(.py文件
* C 或 C++ 擴展(已編譯為共享庫或 DLL 文件
* 包(包含多個模塊)
* 內建模塊(使用 C 編寫並已鏈接到 Python 解釋器中

當導入模塊時,解釋器按照 sys.path 列表中的目錄順序來查找導入文件: 
>>> import sys
>>> print(sys.path)

# Linux:
['', '/usr/local/lib/python3.4',
'/usr/local/lib/python3.4/plat-sunos5',
'/usr/local/lib/python3.4/lib-tk',
'/usr/local/lib/python3.4/lib-dynload',
'/usr/local/lib/python3.4/site-packages']


# Windows:
['', 'C:\\WINDOWS\\system32\\python34.zip', 'C:\\Documents and Settings\\weizhong', 'C:\\Python34\\DLLs', 'C:\\Python34\\lib', 'C:\\Python34\\lib\\plat-win', 'C:\\Python34\\lib\\lib-tk', 'C:\\Python34\\Lib\\site-packages\\pythonwin', 'C:\\Python34', 'C:\\Python34\\lib\\site-packages', 'C:\\Python34\\lib\\site-packages\\win32', 'C:\\Python34\\lib\\site-packages\\win32\\lib', 'C:\\Python34\\lib\\site-packages\\wx-2.6-msw-unicode']

其中 list 第一個元素空字符串代表當前目錄。 

關於.pyc 文件與.pyo 文件 
.py 文件的彙編,只有在 import 語句執行時進行,當 .py 文件第一次被導入時,它會被編譯為 binary,並將結果寫入同名的 .pyc 文件中。後來每次導入操作都會直接執行 .pyc 文件(當 .py 文件的修改時間發生改變,這樣會生成新的 .pyc 文件),在解釋器使用 -O 選項時,將使用同名的 .pyo 文件,這個文件去掉了斷言(assert)、斷行號以及其他調試信息,體積更小,運行更快。(使用 -OO 選項,生成的 .pyo 文件會忽略文檔信息) 

導入模塊 
模塊通常為單獨的 .py 文件,可以用 import 直接引用,可以作為模塊的文件類型有 .py、.pyo、.pyc、.pyd、.so、.dll. 在導入模塊時,解釋器做以下工作: 
1. 已導入模塊的名稱創建新的命名空間,通過該命名空間就可以訪問導入模塊的屬性和方法。
2. 在新創建的命名空間中執行源代碼文件。
3. 創建一個名為源代碼文件的對象,該對象引用模塊的名字空間,這樣就可以通過這個對象訪問模塊中的函數及變量

import 語句可以在程序的任何位置使用,你可以在程序中多次導入同一個模塊,但模塊中的代碼僅僅在該模塊被首次導入時執行。後面的 import 語句只是簡單的創建一個到模塊名字空間的引用而已。sys.modules 字典中保存著所有被導入模塊的模塊名到模塊對象的映射。 

導入包 
多個相關聯的模塊組成一個包,以便於維護和使用,同時能有限的避免命名空間的衝突。一般來說,包的結構可以是這樣的: 
  1. # tree mt/  
  2. mt/  
  3. ├── a.py  
  4. ├── a.pyc  
  5. ├── __init__.py  
  6. └── __init__.pyc  
  7.   
  8. 0 directories, 4 files  
- mt/__init__.py 
  1. import re  
  2. import sys  
  3.   
  4. __all__ = ['re''sys']  
  5.   
  6.   
  7. print('{} is loaded'.format(__file__))  
- mt/a.py 
  1. from mt import *  
  2.   
  3. class Person:  
  4.     def __init__(self, name):  
  5.         self.name = name  
  6.   
  7.     def __str__(self):  
  8.         return "Person({})".format(self.name)  
  9.   
  10.   
  11. print('{} is executed'.format(__file__))  
有以下幾種導入方式: 
>>> import mt.a # 將模塊 mt.a 導入全局命名空間,例如訪問 a 中屬性時用 mt.a.Person
mt/__init__.pyc is loaded
mt/a.pyc is executed

>>> mt.a.Person

>>> a.Person
Traceback (most recent call last):
File "", line 1, in
NameError: name 'a' is not defined

>>> from mt import a # 將模塊 a 導入全局命名空間,例如訪問 a 中屬性時用 a.Person
>>> a.Person

>>> Person
Traceback (most recent call last):
File "", line 1, in
NameError: name 'Person' is not defined

>>> from mt.a import Person # 將模塊 a 的屬性直接導入到命名空間中,例如訪問 a 中屬性时直接用 Person
>>> Person


Supplement 
Python Tutorial Doc - Modules

沒有留言:

張貼留言

[ Python 文章收集 ] List Comprehensions and Generator Expressions

Source From  Here   Preface   Do you know the difference between the following syntax?  view plain copy to clipboard print ? [x  for ...