1. 程式人生 > 程式設計 >淺談Python __init__.py的作用

淺談Python __init__.py的作用

我們經常在python的模組目錄中會看到 "__init__.py" 這個檔案,那麼它到底有什麼作用呢?

1. 標識該目錄是一個python的模組包(module package)

如果你是使用python的相關IDE來進行開發,那麼如果目錄中存在該檔案,該目錄就會被識別為 module package 。

2. 簡化模組匯入操作

假設我們的模組包的目錄結構如下:

.
└── mypackage
  ├── subpackage_1
  │  ├── test11.py
  │  └── test12.py
  ├── subpackage_2
  │  ├── test21.py
  │  └── test22.py
  └── subpackage_3
    ├── test31.py
    └── test32.py

如果我們使用最直接的匯入方式,將整個檔案拷貝到工程目錄下,然後直接匯入:

from mypackage.subpackage_1 import test11
from mypackage.subpackage_1 import test12
from mypackage.subpackage_2 import test21
from mypackage.subpackage_2 import test22
from mypackage.subpackage_3 import test31
from mypackage.subpackage_3 import test32

當然這個例子裡面檔案比較少,如果模組比較大,目錄比較深的話,可能自己都記不清該如何匯入。(很有可能,哪怕只想匯入一個模組都要在目錄中找很久)

這種情況下,__init__.py 就很有作用了。我們先來看看該檔案是如何工作的。

2.1 __init__.py 是怎麼工作的?

實際上,如果目錄中包含了 __init__.py 時,當用 import 匯入該目錄時,會執行 __init__.py 裡面的程式碼。

我們在mypackage目錄下增加一個 __init__.py 檔案來做一個實驗:

.
└── mypackage
  ├── __init__.py
  ├── subpackage_1
  │  ├── test11.py
  │  └── test12.py
  ├── subpackage_2
  │  ├── test21.py
  │  └── test22.py
  └── subpackage_3
    ├── test31.py
    └── test32.py

mypackage/__init__.py 裡面加一個print,如果執行了該檔案就會輸出:

print("You have imported mypackage")

下面直接用互動模式進行 import

>>> import mypackage
You have imported mypackage

很顯然,__init__.py 在包被匯入時會被執行。

2.2 控制模組匯入

我們再做一個實驗,在 mypackage/__init__.py 新增以下語句:

from subpackage_1 import test11

我們匯入 mypackage 試試:

>>> import mypackage
Traceback (most recent call last):
 File "<stdin>",line 1,in <module>
 File "/home/taopeng/Workspace/Test/mypackage/__init__.py",line 2,in <module>
  from subpackage_1 import test11
ImportError: No module named 'subpackage_1'

報錯了。。。怎麼回事?

原來,在我們執行import時,當前目錄是不會變的(就算是執行子目錄的檔案),還是需要完整的包名。

from mypackage.subpackage_1 import test11

綜上,我們可以在__init__.py 指定預設需要匯入的模組  

2.3 偷懶的匯入方法

有時候我們在做匯入時會偷懶,將包中的所有內容匯入

from mypackage import *

這是怎麼實現的呢? __all__ 變數就是幹這個工作的。

__all__ 關聯了一個模組列表,當執行 from xx import * 時,就會匯入列表中的模組。我們將 __init__.py 修改為 。

__all__ = ['subpackage_1','subpackage_2']

這裡沒有包含 subpackage_3,是為了證明 __all__ 起作用了,而不是匯入了所有子目錄。

>>> from mypackage import *
>>> dir()
['__builtins__','__doc__','__loader__','__name__','__package__','__spec__','subpackage_1','subpackage_2']
>>> 
>>> dir(subpackage_1)
['__doc__','__path__','__spec__']

子目錄的中的模組沒有匯入!!!

該例子中的匯入等價於

from mypackage import subpackage_1,subpackage_2

因此,匯入操作會繼續查詢 subpackage_1 和 subpackage_2 中的 __init__.py 並執行。(但是此時不會執行 import *)

我們在 subpackage_1 下新增 __init__.py 檔案:

__all__ = ['test11','test12']

# 預設只匯入test11
from mypackage.subpackage_1 import test11

再來匯入試試

>>> from mypackage import *
>>> dir()
['__builtins__','subpackage_2']
>>> 
>>> dir(subpackage_1)
['__all__','__builtins__','__cached__','__file__','test11']

如果想要匯入子包的所有模組,則需要更精確指定。

>>> from mypackage.subpackage_1 import *
>>> dir()
['__builtins__','test11','test12']

3. 配置模組的初始化操作

在瞭解了 __init__.py 的工作原理後,應該能理解該檔案就是一個正常的python程式碼檔案。

因此可以將初始化程式碼放入該檔案中。

到此這篇關於淺談Python __init__.py的作用的文章就介紹到這了,更多相關Python __init__.py內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!