python 中的import、模塊和包


包和模塊、import

簡單的說,Python 中一個 以 .py 結尾的 Python 文件,就是一個模塊(Module),包含了 Python 對象定義和 Python 語句。
包就是文件夾,但該文件夾下必須存在 __init__.py 文件, 該文件的內容可以為空。__init__.py 用於標識當前文件夾是一個包。

模塊

Python 中一個 以 .py 結尾的 Python 文件,就是一個模塊(Module),包含了 Python 對象定義和 Python 語句。模塊能夠讓你有邏輯地組織 Python 代碼段。把相關的代碼分配到一個模塊里能讓代碼更好用,更易懂。模塊里既能定義函數,類和變量,也能包含可執行的代碼。

模塊的引入

當解釋器遇到 import 語句,如果模塊在當前的搜索路徑就會被導入。搜索路徑是一個解釋器會先進行搜索的所有目錄的列表。不過,不管你執行了多少次 import,一個模塊只會被導入一次(第一次導入后就將模塊名加載到內存了,后續的 import 語句僅是對已經加載大內存中的模塊對象增加了一次引用,不會重新執行模塊內的語句)。這樣可以防止導入模塊被一遍又一遍地執行。如果你想重新執行模塊里頂層部分的代碼,可以用 reload(modul_name) 函數。該函數會重新導入之前導入過的模塊。Python 3 移動到了模塊 importlib 中。

import ... 語句
from ... import ... 語句:Python 的 from 語句讓你從模塊中導入一個指定的部分到當前命名空間中。小心與自定義的對象重名,導致被覆蓋掉了。
from ... import * 語句:導入模塊中定義的全部公有名稱。這種聲明不要過多地使用,可讀性極差,而且導入了過多不必要的對象。不過,有時會與 __all__ 一起使用,此時,會一次性導入 __all__ 變量中列出的所有模塊。

PEP8 建議:

1.py 文件中導入模塊的順序:1)Python內置模塊;2)第三方模塊;3)自定義模塊;且應在每個導入組之間放一行空行。
2.模塊級別的內置屬性(名字有前后雙下划線的),例如 __all__, __author__, __version__,應該放置在模塊的文檔字符串后,任意 import 語句之前,from __future__導入除外。Python強制要求from __future__導入必須在任何代碼之前,只能在模塊級文檔字符串之后。

from __future__ import barry_as_FLUFL

__all__ = ['a', 'b', 'c']
__version__ = '0.1 '
__author__ = 'Cardinal Biggles'

import os
import sys
搜索路徑

當你導入一個模塊,Python 解析器對模塊位置的搜索順序是:
1、當前目錄;
2、如果不在當前目錄,Python 則搜索在 shell 變量 PYTHONPATH 下的每個目錄
3、如果都找不到,Python 會查看默認路徑。UNIX下,默認路徑一般為/usr/local/lib/python/。

模塊搜索路徑存儲在 system 模塊的 sys.path (list,指明了所有查找 module,package 的路徑)變量中。變量里包含當前目錄,PYTHONPATH和由安裝過程決定的默認目錄。

包是一個分層次的文件目錄結構,它定義了一個由模塊及子包,和子包下的子包等組成的 Python 的應用環境。
簡單的說,包就是文件夾,但該文件夾下必須存在 __init__.py 文件, 該文件的內容可以為空,也可以有 Python 代碼,原則是盡量保持 __init__.py 文件的精簡。__init__.py 用於標識當前文件夾是一個包。若這個文件不存在,那么這個目錄只是一個目錄而不是一個包。有如下目錄的 m3.py、test1.py

├─root                               
│  ├─pack1
│  │  ├─pack2
│  │  │  ├─pack3
│  │  │  │  ├─__init__.py 
│  │  │  │  ├─m3.py
│  │  ├─__init__.py
│  │  ├─m2.py
│  ├─test1.py

# m3.py
def pack3_print():
    print("我是m3!")

pack_3 中的 __init__.py 文件中為空,m3.py 有一個打印函數 pack3_print()。由於調用包的其他模塊所在的絕對路徑是千變萬化的,所以在包的內部調用自身其他文件中的函數、常量、類,應該使用相對路徑,而不是絕對路徑。

1.現在若要在 test1.py 文件夾調用這個函數,可以這么做:

1)按照路徑導入即可:

from root.pack1.pack2.pack3.m3 import pack3_print

pack3_print()

or

import pack1.pack2.pack3.m3

pack1.pack2.pack3.m3.pack3_print()

2)在 test1.py 同級目錄的 pack1 的文件夾下創建一個 __init__.py 文件, 文件內容是:

from .pack2.pack3.m3 import pack3_print

再在 test1.py 中引入 pack3_print 函數:

from pack1 import pack3_print

pack3_print()

from . import <some-module> 句法表示相對導入。語句中的 . 表示當前包。還有 from .. import <some-module> ,這里的 .. 表示當前包的上一層。
包內部的文件之間互相導入可以使用相對導入,並且通過提前把函數、常量、類導入到 __init__.py 中后,包外面再想導入這些內容時,就可以直接用 from 包名 import 函數名 導入了,可以精簡代碼。

2.我們再在 pack2 下創建一個 m2.py 文件,在 m2 中調用 pack3_print 函數:

# 在 m2.py 使用相對路徑直接導入:
from .pack2.pack3.m3 import pack3_print

def pack2_print():
    print('我是m2!')
    pack3_print()

不過,由於前面我們已經在 __init__.py 導入過 pack3_print 函數了,所以,我們可以在 m2 中這樣直接導入:

from . import pack3_print -- 注意一下循環導入依賴的問題?

我們再修改上面的 __init__.py,把 pack2_print 函數導入進去:

from .pack2.pack3.m3 import pack3_print
from .m2 import pack2_print

最后,在 test1.py 中調用這個 pack2_print 函數:

from pack1 import pack3_print
from pack1 import pack2_print

pack3_print()
pack2_print()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM