【发布时间】:2016-02-18 01:16:36
【问题描述】:
我有 answered 一个关于 Python 中的绝对导入的问题,我认为我根据阅读 the Python 2.5 changelog 和随附的 PEP 理解了这个问题。然而,在安装 Python 2.5 并尝试制作一个正确使用 from __future__ import absolute_import 的示例后,我意识到事情并不是那么清楚。
直接来自上面链接的更改日志,这句话准确地总结了我对绝对导入更改的理解:
假设你有一个这样的包目录:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py这定义了一个名为
pkg的包,其中包含pkg.main和pkg.string子模块。考虑 main.py 模块中的代码。如果它执行语句
import string会发生什么?在 Python 2.4 及更早版本中,它会首先查看包的目录以执行相对导入,找到 pkg/string.py,将该文件的内容导入为pkg.string模块,并且该模块绑定到名称 @987654333 @ 在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 (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 更新日志中,我们发现以下内容(强调添加):
在 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 (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 版本的说法完全矛盾。更重要的是,尽管警告说绝对导入将成为“新的默认”行为,但我在使用 Python 2.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'
我已经测试了这个的其他变体。而不是string.py,我创建了一个空模块——一个名为string的目录,只包含一个空的__init__.py——而不是从main.py发出导入,我有cd'd到pkg并直接从 REPL 运行导入。这些变化(或它们的组合)都没有改变上述结果。我无法将这与我所读到的关于 __future__ 指令和绝对导入的内容相协调。
在我看来,the following 很容易解释这一点(这来自 Python 2 文档,但在 Python 3 的相同文档中此语句保持不变):
系统路径
(...)
在程序启动时初始化,此列表的第一项
path[0]是包含用于调用 Python 解释器的脚本的目录。如果脚本目录不可用(例如,如果交互调用解释器或从标准输入读取脚本),path[0]是空字符串,指示 Python 首先搜索当前目录中的模块。
那么我错过了什么?为什么__future__ 声明看起来不像它所说的那样,这两个文档部分之间以及描述和实际行为之间的矛盾的解决方案是什么?
【问题讨论】:
标签: python python-2.7 python-import python-2.5