詳解Python中的相對導入和絕對導入
前言
Python 相對導入與絕對導入,這兩個概念是相對于包內(nèi)導入而言的。包內(nèi)導入即是包內(nèi)的模塊導入包內(nèi)部的模塊。
Python import 的搜索路徑
- 在當前目錄下搜索該模塊
- 在環(huán)境變量 PYTHONPATH 中指定的路徑列表中依次搜索
- 在 Python 安裝路徑的 lib 庫中搜索
Python import 的步驟
python 所有加載的模塊信息都存放在 sys.modules
結(jié)構(gòu)中,當 import 一個模塊時,會按如下步驟來進行
- 如果是
import A
,檢查sys.modules
中是否已經(jīng)有 A,如果有則不加載,如果沒有則為 A 創(chuàng)建 module 對象,并加載 A - 如果是
from A import B
,先為 A 創(chuàng)建 module 對象,再解析A,從中尋找B并填充到 A 的__dict__
中
相對導入與絕對導入
絕對導入的格式為 import A.B
或 from A import B
,相對導入格式為 from . import B
或 from ..A import B
,.代表當前模塊,..代表上層模塊,...代表上上層模塊,依次類推。
相對導入可以避免硬編碼帶來的維護問題,例如我們改了某一頂層包的名,那么其子包所有的導入就都不能用了。但是 存在相對導入語句的模塊,不能直接運行,否則會有異常:
ValueError: Attempted relative import in non-package
這是什么原因呢?我們需要先來了解下導入模塊時的一些規(guī)則:
在沒有明確指定包結(jié)構(gòu)的情況下,Python 是根據(jù) __name__
來決定一個模塊在包中的結(jié)構(gòu)的,如果是 __main__
則它本身是頂層模塊,沒有包結(jié)構(gòu),如果是A.B.C 結(jié)構(gòu),那么頂層模塊是 A?;旧献裱@樣的原則:
- 如果是絕對導入,一個模塊只能導入自身的子模塊或和它的頂層模塊同級別的模塊及其子模塊
- 如果是相對導入,一個模塊必須有包結(jié)構(gòu)且只能導入它的頂層模塊內(nèi)部的模塊
如果一個模塊被直接運行,則它自己為頂層模塊,不存在層次結(jié)構(gòu),所以找不到其他的相對路徑。
Python2.x 缺省為相對路徑導入,Python3.x 缺省為絕對路徑導入。絕對導入可以避免導入子包覆蓋掉標準庫模塊(由于名字相同,發(fā)生沖突)。如果在 Python2.x 中要默認使用絕對導入,可以在文件開頭加入如下語句:
from __future__ import absolute_import
from __future__ import absolute_import
這句 import 并不是指將所有的導入視為絕對導入,而是指禁用 implicit relative import
(隱式相對導入), 但并不會禁掉 explicit relative import
(顯示相對導入)。
那么到底什么是隱式相對導入,什么又是顯示的相對導入呢?我們來看一個例子,假設有如下包結(jié)構(gòu):
thing ├── books │ ├── adventure.py │ ├── history.py │ ├── horror.py │ ├── __init__.py │ └── lovestory.py ├── furniture │ ├── armchair.py │ ├── bench.py │ ├── __init__.py │ ├── screen.py │ └── stool.py └── __init__.py
那么如果在 stool 中引用 bench,則有如下幾種方式:
import bench # 此為 implicit relative import from . import bench # 此為 explicit relative import from furniture import bench # 此為 absolute import
隱式相對就是沒有告訴解釋器相對于誰,但默認相對與當前模塊;而顯示相對則明確告訴解釋器相對于誰來導入。以上導入方式的第三種,才是官方推薦的,第一種是官方強烈不推薦的,Python3 中已經(jīng)被廢棄,這種方式只能用于導入 path 中的模塊。
相對與絕對僅針對包內(nèi)導入而言
最后再次強調(diào),相對導入與絕對導入僅針對于包內(nèi)導入而言,要不然本文所討論的內(nèi)容就沒有意義。所謂的包,就是包含 __init__.py
文件的目錄,該文件在包導入時會被首先執(zhí)行,該文件可以為空,也可以在其中加入任意合法的 Python 代碼。
相對導入可以避免硬編碼,對于包的維護是友好的。絕對導入可以避免與標準庫命名的沖突,實際上也不推薦自定義模塊與標準庫命令相同。
前面提到含有相對導入的模塊不能被直接運行,實際上含有絕對導入的模塊也不能被直接運行,會出現(xiàn) ImportError:
ImportError: No module named XXX
這與絕對導入時是一樣的原因。要運行包中包含絕對導入和相對導入的模塊,可以用 python -m A.B.C
告訴解釋器模塊的層次結(jié)構(gòu)。
有人可能會問:假如有兩個模塊 a.py 和 b.py 放在同一個目錄下,為什么能在 b.py 中 import a
呢?
這是因為這兩個文件所在的目錄不是一個包,那么每一個 python 文件都是一個獨立的、可以直接被其他模塊導入的模塊,就像你導入標準庫一樣,它們不存在相對導入和絕對導入的問題。相對導入與絕對導入僅用于包內(nèi)部。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家學習或者使用python能有一定的幫助,如果有疑問大家可以留言交流。
相關文章
VSCode中autopep8無法運行問題解決方案(提示Error: Command failed,usage)
這篇文章主要介紹了VSCode中autopep8無法運行問題解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03Python利用多進程將大量數(shù)據(jù)放入有限內(nèi)存的教程
這篇文章主要介紹了Python利用多進程將大量數(shù)據(jù)放入有限內(nèi)存的教程,使用了multiprocessing和pandas來加速內(nèi)存中的操作,需要的朋友可以參考下2015-04-04Python命令行參數(shù)解析之a(chǎn)rgparse模塊詳解
這篇文章主要介紹了Python命令行參數(shù)解析之a(chǎn)rgparse模塊詳解,argparse?是?Python?的一個標準庫,用于命令行參數(shù)的解析,這意味著我們無需在代碼中手動為變量賦值,而是可以直接在命令行中向程序傳遞相應的參數(shù),再由變量去讀取這些參數(shù),需要的朋友可以參考下2023-08-08Matlab、Python為工具解析數(shù)據(jù)可視化之美
下面介紹一些數(shù)據(jù)可視化的作品(包含部分代碼),主要是地學領域,可遷移至其他學科,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-11-11python 根據(jù)excel中顏色區(qū)分讀取的操作
這篇文章主要介紹了python 根據(jù)excel中顏色區(qū)分讀取的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03