Python模塊包中__init__.py文件的作用

http://blog.csdn.net/yxmmxy7913/article/details/4233420

http://www.cnblogs.com/wanpython/archive/2012/12/02/2798305.html 


在eclipse中用pydev開發Python腳本時,我遇到了一個這樣的現象,當我新建一個pydev package時,總會自動地生成一個空的__init__.py文件,因爲是python新手,所以很不瞭解這個空文件的作用是什麼,因爲沒有什麼東西可寫在這裏,所以我直接把這個文件給刪掉了,結果我的包圖標自動變爲文件夾圖標了,這是怎麼回事呢!

 

原來在python模塊的每一個包中,都有一個__init__.py文件(這個文件定義了包的屬性和方法)然後是一些模塊文件和子目錄,假如子目錄中也有 __init__.py 那麼它就是這個包的子包了。當你將一個包作爲模塊導入(比如從 xml導入 dom )的時候,實際上導入了它的 __init__.py 文件。

一個包是一個帶有特殊文件 __init__.py 的目錄。__init__.py 文件定義了包的屬性和方法。其實它可以什麼也不定義;可以只是一個空文件,但是必須存在。如果 __init__.py 不存在,這個目錄就僅僅是一個目錄,而不是一個包,它就不能被導入或者包含其它的模塊和嵌套包。

 

 

_init__.py 文件:

__init__.py 控制着包的導入行爲。假如 __init__.py 爲空,那麼僅僅導入包是什麼都做不了的。

>>> import Package1

>>> Package1.Module1

Traceback (most recent call last):
  File "D:/Work Space/Python practice/MyPractice/src/test.py", line 8, in <module>
    aa=Package1.Module1
AttributeError: 'module' object has no attribute 'Module1'

我們需要在 __init__.py 裏把 Module1 預先導入:

#文件 __init__.py

import Module1

測試

>>> import Package1
>>> aa=Package1.Module1
>>> print aa

__init__.py 中還有一個重要的變量,叫做 __all__。我們有時會使出一招“全部導入”,也就是這樣:

from PackageName import *

這時 import 就會把註冊在包 __init__.py 文件中 __all__ 列表中的子模塊和子包導入到當前作用域中來。比如:

#文件 __init__.py

__all__ = ["Module1", "Module2", "subPackage1", "subPackage2"]

測試:

>>> from Package1 import *

>>>

 

test1111111111111111111111
test222222

__init__.py 文件會在導入時被執行。



python中的Module是比較重要的概念。常見的情況是,事先寫好一個.py文 件,在另一個文件中需要import時,將事先寫好的.py文件拷貝 到當前目錄,或者是在sys.path中增加事先寫好的.py文件所在的目錄,然後import。這樣的做法,對於少數文件是可行的,但如果程序數目很 多,層級很複雜,就很吃力了。
有沒有辦法,像Java的Package一樣,將多個.py文件組織起來,以便在外部統一調用,和在內部互相調用呢?答案是有的。
主要是用到python的包的概念,python __init__.py在包裏起一個比較重要的作用
要弄明白這個問題,首先要知道,python在執行import語句時,到底進行了什麼操作,按照python的文檔,它執行了如下操作:
第1步,創建一個新的,空的module對象(它可能包含多個module);
第2步,把這個module對象插入sys.module中
第3步,裝載module的代碼(如果需要,首先必須編譯)
第4步,執行新的module中對應的代碼。

在執行第3步時,首先要找到module程序所在的位置,其原理爲:
如 果需要導入的module的名字是m1,則解釋器必須找到m1.py,它首先在當前目錄查找,然後是在環境變量PYTHONPATH中查找。 PYTHONPATH可以視爲系統的PATH變量一類的東西,其中包含若干個目錄。如果PYTHONPATH沒有設定,或者找不到m1.py,則繼續搜索 與python的安裝設置相關的默認路徑,在Unix下,通常是/usr/local/lib/python。
事實上,搜索的順序是:當前路徑 (以及從當前目錄指定的sys.path),然後是PYTHONPATH,然後是python的安裝設置相關的默認路徑。正因爲存在這樣的順序,如果當前 路徑或PYTHONPATH中存在與標準module同樣的module,則會覆蓋標準module。也就是說,如果當前目錄下存在xml.py,那麼執 行import xml時,導入的是當前目錄下的module,而不是系統標準的xml。

瞭解了這些,我們就可以先構建一個package,以普通module的方式導入,就可以直接訪問此package中的各個module了。

Python中的package定義很簡單,其層次結構與程序所在目錄的層次結構相同,這一點與Java類似,唯一不同的地方在於,python中的package必須包含一個__init__.py的文件。
例如,我們可以這樣組織一個package:

package1/
    __init__.py
    subPack1/
        __init__.py
        module_11.py
        module_12.py
        module_13.py
    subPack2/
        __init__.py
        module_21.py
        module_22.py
    ……

__init__.py可以爲空,只要它存在,就表明此目錄應被作爲一個package處理。當然,__init__.py中也可以設置相應的內容,下文詳細介紹。

好了,現在我們在module_11.py中定義一個函數:

def funA():
    print "funcA in module_11"
    return

在頂層目錄(也就是package1所在的目錄,當然也參考上面的介紹,將package1放在解釋器能夠搜索到的地方)運行python:

>>>from package1.subPack1.module_11 import funcA
>>>funcA()
funcA in module_11

這樣,我們就按照package的層次關係,正確調用了module_11中的函數。

細心的用戶會發現,有時在import語句中會出現通配符*,導入某個module中的所有元素,這是怎麼實現的呢?
答案就在__init__.py中。我們在subPack1的__init__.py文件中寫

__all__ = ['module_13', 'module_12']

然後進入python

>>>from package1.subPack1 import *
>>>module_11.funcA()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named module_11

也就是說,以*導入時,package內的module是受__init__.py限制的。

好了,最後來看看,如何在package內部互相調用。
如果希望調用同一個package中的module,則直接import即可。也就是說,在module_12.py中,可以直接使用

import module_11

如果不在同一個package中,例如我們希望在module_21.py中調用module_11.py中的FuncA,則應該這樣:

from module_11包名.module_11 import funcA


作者:老王@python python教程
老王python,提供pythn相關的python教程和python下載,希望大家能夠喜歡


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章