背景:
在學習tf的時候,看到了from __future__ import absolute_import
,所以登記學習一下。
概覽:
一般模塊導入規則:
import xxx
時搜索文件的優先級如下:
1.在當前目錄下搜索該模塊
2.在環境變量 PYTHONPATH 中指定的路徑列表中依次搜索
3.在 Python 安裝路徑的 lib 庫中搜索
在 Python 程序啟動時進行配置,自動將 top-level file 的 home 目錄(或用一個''表示當前工作目錄)、PYTHONPATH 設置的目錄、.pth 文件里的目錄、標准庫目錄合並成一個 list ,組成每次 import 時 Python 搜索的目錄列表,放到sys.path 中
關於sys.path的有關調試
- python2 版本
~ # python
$ python
Python 2.7.12 (default, Oct 8 2019, 14:14:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']
- python3 版本
$ python3
Python 3.5.2 (default, Oct 8 2019, 13:06:37)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']
Python import 的步驟:
python 所有加載的模塊信息都存放在 sys.modules 結構中,當 import 一個模塊時,會按如下步驟來進行
如果是 import A,檢查 sys.modules 中是否已經有 A;如果有則不加載,如果沒有則為 A 創建 module 對象,並加載 A
如果是 from A import B,先為 A 創建 module 對象,再解析A,從中尋找B並填充到 A 的 dict 中
Python中的絕對導入與相對導入:
相對導入與絕對導入,這兩個概念是相對於包內導入而言的。包內導入即是包內的模塊導入包內部的模塊。
所謂的包,就是包含 init.py 文件的目錄,該文件在包導入時會被首先執行,該文件可以為空,也可以在其中加入任意合法的 Python 代碼。
相對導入可以避免硬編碼,對於包的維護是友好的。絕對導入可以避免與標准庫命名的沖突,實際上也不推薦自定義模塊與標准庫命令相同。
絕對導入:指明頂層 package 名。比如 import a,Python 會在 sys.path里尋找所有名為 a 的頂層模塊。
import A.B
或
from A import B
相對導入:在不指明 package 名的情況下導入自己這個 package 的模塊,表示只在 package 的內部目錄中搜索,並且不會搜索位於 sys.path 上某處同名的模塊,直接效果就是包模塊覆蓋了外部的模塊。
from . import B
或
from ..A import B
# .代表當前模塊,..代表上層模塊,...代表上上層模塊,依次類推。
比如一個 package 下有 a.py 和 b.py 兩個文件,在 a.py 里 from . import b 即是相對導入 b.py。
# a.py from . import b
Q: 為什么能在 b.py 中 import a 呢?
A: 這是因為這兩個文件所在的目錄不是一個包,那么每一個 python 文件都是一個獨立的、可以直接被其他模塊導入的模塊。就像導入標准庫一樣,它們不存在相對導入和絕對導入的問題。相對導入與絕對導入僅用於包內部。
Python2.x 默認為相對路徑導入,Python3.x 默認為絕對路徑導入。
絕對導入可以避免導入子包覆蓋掉標准庫模塊(由於名字相同,發生沖突)。
如果在 Python2.x 中要默認使用絕對導入,可以在文件開頭加入如下語句:
from __future__ import absolute_import
# 在 3.0 以前的舊版本中啟用相對導入等特性所必須的 future 語句,表示打開了 Python 3.0 的默認絕對搜索路徑特性
需要注意的是文件夾被python解釋器視作package需要滿足兩個條件:
- 1.文件夾中必須有__init__.py文件,該文件可以為空,但必須存在該文件。
- 2.不能作為頂層模塊來執行該文件夾中的py文件(即不能作為主函數的入口)。
所以,當用.. 或 ../..返回上級去導入的時候,如果到了程序的入口就會報錯:ValueError: attempted relative import beyond top-level package
這是因為第2條的原因,也就是相對導入的時候不能返回到頂層目錄去導入,否則會報錯。
所以,用絕對導入的人比較多,相對導入中一個點(同級導入)用的比較多。