我有一个关于Python中绝对导入的回答了问题,在阅读Python 2.5更新日志和附带的佩普的基础上,我认为我理解了这个问题。然而,在安装Python2.5并尝试创建一个正确使用from __future__ import absolute_import
的示例时,我意识到事情并不是那么清楚。
直接从上面链接的ChangeLog中,这句话准确地总结了我对绝对进口变化的理解:
假设您有一个这样的软件包目录:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
这定义了名为
pkg
的包,其中包含pkg.main
和pkg.string
子模块。考虑main.py模块中的代码。如果它执行ABC0__语句,会发生什么情况?在Python2.4及更早版本中,它将首先查找包的目录以执行相对导入,找到PKG/string.py,将该文件的内容导入为
pkg.string
模块,并且该模块被绑定到pkg.main
模块的命名空间中的名称"string"
。
所以我创建了这个精确的目录结构:
$ ls -R
.:
pkg/
./pkg:
__init__.py main.py string.py
__init__.py
和string.py
为空。main.py
包含以下代码:
import string
print string.ascii_uppercase
正如预期的那样,在Python2.5中运行它会失败,并出现__abc0:
$ python2.5 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
然而,在2.5 ChangeLog中,我们进一步发现了以下内容(着重号另加):
在Python2.5中,您可以使用
from __future__ import absolute_import
指令将import
的行为切换为绝对导入。这种绝对导入行为将成为未来版本(可能是Python2.7)的默认设置。一旦绝对导入成为默认设置,import string
将始终查找标准库的版本。
因此,我创建了pkg/main2.py
,与main.py
相同,但具有额外的未来进口指令。现在看起来是这样的:
from __future__ import absolute_import
import string
print string.ascii_uppercase
然而,用Python2.5运行它..失败,出现AttributeError
:
$ python2.5 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
这与import string
将总是找到启用了绝对导入的STD-lib版本的说法完全矛盾。更重要的是,尽管有绝对导入将成为“新的默认”行为的警告,但我在使用Python2.7(使用或不使用__future__
指令)时都遇到了同样的问题:
$ python2.7 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
$ python2.7 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
以及Python 3.5,使用或不使用(假设在两个文件中更改了print
语句):
$ python3.5 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'
$ python3.5 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'
我已经测试了它的其他变体。我没有创建__abc0,而是创建了一个空模块--一个名为__abc1的目录,其中只包含一个空__abc2--并且我没有从__abc3发出导入,而是将abc4__到__abc5,并直接从repl运行导入。这些变化(或它们的组合)都不会改变上述结果。我无法将此与我所读到的有关__future__
指令和绝对导入的内容相协调。
在我看来,这很容易用以下内容来解释(这来自Python 2文档,但这条语句在Python 3的相同文档中保持不变):
系统路径
(...)
正如程序启动时初始化的一样,该列表的第一项(__abc0)是包含用于调用Python解释器的脚本的目录。如果脚本目录不可用(例如,如果以交互方式调用解释器或如果从标准输入读取脚本),则
path[0]
是空字符串,它指示Python首先搜索当前目录中的模块。
那我错过了什么?为什么__future__
语句似乎并不像它所说的那样,文档的这两个部分之间以及描述的行为和实际行为之间的矛盾是如何解决的?