談談python中的__init__.py

類似java中的package,python中也通過import語句引入各種python module.

python中的Module是比較重要的概念。常見的情況是,事先寫好一個.py文 件,在另一個文件中需要import時,將事先寫好的.py文件拷貝 到當前目錄,或者是在sys.path中增加事先寫好的.py文件所在的目錄,然後import。這樣的做法,對於少數文件是可行的,但對於比較大的項目來說,需要有更具效率的方法。這就涉及到python的包的概念,而 __init__.py文件在python 包中起一個比較重要的作用

python在執行import語句時,按照python的文檔,它執行了如下操作:
第1步,創建一個新的,空的module對象(它可能包含多個module);
第2步,把這個module對象插入sys.module中
第3步,裝載module的代碼(如果需要,首先必須編譯,我們可以看到程序運行後會多出很多.class文件)
第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的文件(用於表示此目錄是一個python package)。
例如,我們可以這樣組織一個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中也可以設置相應的內容,下面以python的serial模塊pyserial爲例進行說明:

import sys
import importlib

from serial.serialutil import *
#~ SerialBase, SerialException, to_bytes, iterbytes

__version__ = '3.4'

VERSION = __version__

# pylint: disable=wrong-import-position
if sys.platform == 'cli':
    from serial.serialcli import Serial
else:
    import os
    # chose an implementation, depending on os
    if os.name == 'nt':  # sys.platform == 'win32':
        from serial.serialwin32 import Serial
    elif os.name == 'posix':
        from serial.serialposix import Serial, PosixPollSerial, VTIMESerial  # noqa
    elif os.name == 'java':
        from serial.serialjava import Serial
    else:
        raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name))


protocol_handler_packages = [
    'serial.urlhandler',
]


def serial_for_url(url, *args, **kwargs):

...
上面是pyserial中serial module中的__init__.py,其會在import module過程中被執行,可用於選取需要裝載的模塊,比如在python環境下import serial,則__init__.py中的

elif os.name == 'java':
        from serial.serialjava import Serial
語句就會被執行,然後進一步加載Serial類。
另外,在該__init__.py中還定義了serial_for_url函數,引用過serial 模塊的腳步也可以當成正常的函數調用



發佈了121 篇原創文章 · 獲贊 50 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章