我回答了一個關於Python中絕對導入的問題,我認為我在閱讀Python 2.5 變更日誌 和隨附的 PEP。但是,在安裝 Python 2.5 並嘗試製作一個正確使用 from __future__ import absolute_import
的示例時,我意識到事情並不是那麼清楚。
直接從上面鏈接的更改日誌中,這語句準確地總結了我對絕對導入更改的理解:
假設你有一個這樣的包目錄:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
這定義了一個名為
pkg
的包,其中包含pkg.main
和pkg.string
submodules.考慮 main.py 模塊中的代碼。如果它執行語句
import string
會發生什麼?在 Python 2.4 及更早版本中,它將首先查看包的目錄以執行相對導入,找到 pkg/string.py,將該文件的內容作為pkg.string
模塊導入,並且該模塊與名稱綁定"string"
在pkg.main
模塊的名稱中
所以我創建了這個精確的目錄結構:
$ ls -R .: pkg/ ./pkg: __init__.py main.py string .py
__init__.py
和 string.py
為空。 main.py
包含以下代碼:
import string print string.ascii_uppercase
正如預期的那樣,用 Python 2.5 運行它失敗並出現 AttributeError
:
$ python2.5 pkg/main.py Traceback(最近一次調用最後):文件“pkg/main.py”,第 2 行, 在<模塊> print string.ascii_uppercase AttributeError: "module" object has no attribute "ascii_uppercase"
然而,在 2.5 的更新日誌中,我們發現了這個(強調添加):
在 Python 2.5 中,您可以使用
from __future__ import absolute_import
指令將import
的行為切換為絕對導入。這種絕對導入行為將在未來的版本(可能是 Python 2.7)。一旦默認導入絕對導入,import string
將始終找到標準庫的版本。
我因此創建了 pkg/main2.py
,與 main.py
相同,但帶有額外的未來導入指令。它現在看起來像這樣:
from __future__ import absolute_import import string print string.ascii_uppercase
用 Python 2.5 運行它,但是......失敗了AttributeError
:
$ python2.5 pkg/main2.py Traceback(最近一次調用最後):文件“pkg/main2.py”,第 3 行,在 < ;模塊> print string.ascii_uppercase AttributeError: "module" object has no attribute "ascii_uppercase"
這與 import string
將 always 找到啟用了絕對導入的 std-lib 版本。更重要的是,儘管警告說絕對導入計劃成為“新的默認”行為,但我在使用 Python 2.7 時遇到了同樣的問題,無論是否使用 __future__
指令:
$ python2.7 pkg/main.py Traceback(最近一次調用最後):文件“pkg/main.py”,第 2 行,在<module>打印 string.ascii_uppercase AttributeError:“module”對象沒有屬性“ascii_uppercase”$ python2.7 pkg/main2.py Traceback(最近一次調用最後):文件“pkg/main2.py”,第 3 行,在<module>打印 string.ascii_uppercase AttributeError:“module”對象沒有屬性 "ascii_uppercase"
以及 Python 3.5,有或沒有(假設 print
語句在兩個文件中都已更改):
$ python3.5 pkg/main.py Traceback(最近一次調用最後):文件“pkg/main.py”,第 2 行,在 <module> print(string.ascii_uppercase) AttributeError: module "string " 沒有屬性 "ascii_uppercase" $ python3.5 pkg/main2.py Trac eback(最近一次調用最後一次):文件“pkg/main2.py”,第 3 行,在 <module> print(string.ascii_uppercase) AttributeError: module "string" has no attribute "ascii_uppercase"
我已經測試過這個的其他變體。我創建了一個空模塊,而不是 string.py
——一個名為 string
的目錄,其中只包含一個空的 __init__.py
——而是從 main.py
發出導入,我有 cd
"d 到 pkg
並直接從 REPL 運行導入。這些變體都不是(也不是它們的組合)改變了上面的結果。我無法將這與我所讀到的關於 __future__
指令和絕對導入的內容相一致。
在我看來,這很容易解釋由 以下 (這是來自 Python 2 文檔,但是這個Python 3 的相同文檔中的語句保持不變):
sys.path
(...)
在程序啟動時初始化,此列表的第一項,
path[0]
,是包含用於調用 Python 解釋器的腳本的目錄。如果腳本目錄y 不可用(例如,如果以交互方式調用解釋器或從標準輸入讀取腳本),path[0]
是空字符串,指示 Python 在當前目錄優先。
那麼我錯過了什麼?為什麼 __future__
語句看起來不像它所說的那樣,這兩個文檔部分之間以及描述和實際行為之間的矛盾的解決方法是什麼?