Python from __future__ import absolute_import 实际上是做什么的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33743880/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What does from __future__ import absolute_import actually do?
提问by Two-Bit Alchemist
I have answereda question regarding absolute imports in Python, which I thought I understood based on reading the Python 2.5 changelogand accompanying PEP. However, upon installing Python 2.5 and attempting to craft an example of properly using from __future__ import absolute_import
, I realize things are not so clear.
我已经回答了一个关于 Python 中绝对导入的问题,我认为我是根据阅读Python 2.5 更新日志和随附的PEP理解的。但是,在安装 Python 2.5 并尝试制作一个正确使用 的示例后from __future__ import absolute_import
,我意识到事情并不是那么清楚。
Straight from the changelog linked above, this statement accurately summarized my understanding of the absolute import change:
直接从上面链接的更改日志中,此语句准确地总结了我对绝对导入更改的理解:
Let's say you have a package directory like this:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
This defines a package named
pkg
containing thepkg.main
andpkg.string
submodules.Consider the code in the main.py module. What happens if it executes the statement
import string
? In Python 2.4 and earlier, it will first look in the package's directory to perform a relative import, finds pkg/string.py, imports the contents of that file as thepkg.string
module, and that module is bound to the name"string"
in thepkg.main
module's namespace.
假设你有一个这样的包目录:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
这定义了一个名为
pkg
包含pkg.main
和pkg.string
子模块的包。考虑 main.py 模块中的代码。如果它执行语句会发生什么
import string
?在Python 2.4和更早的版本,它会先看看在包的目录进行相对进口,发现包装/ string.py,进口该文件的内容pkg.string
模块,并且该模块被绑定到名字"string"
的pkg.main
模块的名称空间。
So I created this exact directory structure:
所以我创建了这个确切的目录结构:
$ ls -R
.:
pkg/
./pkg:
__init__.py main.py string.py
__init__.py
and string.py
are empty. main.py
contains the following code:
__init__.py
并且string.py
是空的。main.py
包含以下代码:
import string
print string.ascii_uppercase
As expected, running this with Python 2.5 fails with an AttributeError
:
正如预期的那样,使用 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'
However, further along in the 2.5 changelog, we find this (emphasis added):
然而,在 2.5 更新日志中,我们发现这一点(强调):
In Python 2.5, you can switch
import
's behaviour to absolute imports using afrom __future__ import absolute_import
directive. This absolute-import behaviour will become the default in a future version (probably Python 2.7). Once absolute imports are the default,import string
will always find the standard library's version.
在 Python 2.5 中,您可以
import
使用from __future__ import absolute_import
指令将的行为切换为绝对导入。这种绝对导入行为将成为未来版本(可能是 Python 2.7)的默认设置。一旦绝对导入成为默认值,import string
将始终找到标准库的版本。
I thus created pkg/main2.py
, identical to main.py
but with the additional future import directive. It now looks like this:
因此pkg/main2.py
,我创建了,与main.py
附加的未来导入指令相同。现在看起来像这样:
from __future__ import absolute_import
import string
print string.ascii_uppercase
Running this with Python 2.5, however... fails with an AttributeError
:
使用 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'
This pretty flatly contradicts the statement that import string
will alwaysfind the std-lib version with absolute imports enabled. What's more, despite the warning that absolute imports are scheduled to become the "new default" behavior, I hit this same problem using both Python 2.7, with or without the __future__
directive:
这个漂亮的断然反驳该语句import string
将始终找到STD-库版本绝对进口启用。更重要的是,尽管警告说绝对导入将成为“新的默认”行为,但我在使用或不使用该__future__
指令的Python 2.7 中都遇到了同样的问题:
$ 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'
as well as Python 3.5, with or without (assuming the print
statement is changed in both files):
以及 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'
I have tested other variations of this. Instead of string.py
, I have created an empty module -- a directory named string
containing only an empty __init__.py
-- and instead of issuing imports from main.py
, I have cd
'd to pkg
and run imports directly from the REPL. Neither of these variations (nor a combination of them) changed the results above. I cannot reconcile this with what I have read about the __future__
directive and absolute imports.
我已经测试了这个的其他变体。相反的string.py
,我已经创建了一个空的模块-一个新的目录string
仅包含一个空的__init__.py
-而不是从发放的进口main.py
,我有cd
“d到pkg
并直接从REPL运行的进口。这些变化(或它们的组合)都没有改变上述结果。我无法将这与我阅读的有关__future__
指令和绝对导入的内容相协调。
It seems to me that this is easily explicable by the following(this is from the Python 2 docs but this statement remains unchanged in the same docs for Python 3):
在我看来,这很容易通过以下方式解释(这是来自 Python 2 文档,但该声明在 Python 3 的相同文档中保持不变):
sys.path
(...)
As initialized upon program startup, the first item of this list,
path[0]
, is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input),path[0]
is the empty string, which directs Python to search modules in the current directory first.
系统路径
(……)
在程序启动时初始化,此列表的第一项
path[0]
是包含用于调用 Python 解释器的脚本的目录。如果脚本目录不可用(例如,如果以交互方式调用解释器或从标准输入读取脚本),path[0]
则为空字符串,它指示 Python 首先搜索当前目录中的模块。
So what am I missing? Why does the __future__
statement seemingly not do what it says, and what is the resolution of this contradiction between these two sections of documentation, as well as between described and actual behavior?
那么我错过了什么?为什么__future__
声明似乎没有按照它所说的做,这两个文档部分之间以及描述的行为和实际行为之间的这种矛盾的解决方案是什么?
采纳答案by user2357112 supports Monica
The changelog is sloppily worded. from __future__ import absolute_import
does not care about whether something is part of the standard library, and import string
will not always give you the standard-library module with absolute imports on.
变更日志措辞草率。from __future__ import absolute_import
不关心某些东西是否是标准库的一部分,并且import string
不会总是为您提供绝对导入的标准库模块。
from __future__ import absolute_import
means that if you import string
, Python will always look for a top-level string
module, rather than current_package.string
. However, it does not affect the logic Python uses to decide what file is the string
module. When you do
from __future__ import absolute_import
意味着如果你import string
,Python 将始终寻找顶级string
模块,而不是current_package.string
. 但是,它不会影响 Python 用来决定哪个文件是string
模块的逻辑。当你做
python pkg/script.py
pkg/script.py
doesn't look like part of a package to Python. Following the normal procedures, the pkg
directory is added to the path, and all .py
files in the pkg
directory look like top-level modules. import string
finds pkg/string.py
not because it's doing a relative import, but because pkg/string.py
appears to be the top-level module string
. The fact that this isn't the standard-library string
module doesn't come up.
pkg/script.py
看起来不像 Python 包的一部分。按照正常程序,将pkg
目录添加到路径中,.py
目录中的所有文件pkg
看起来都像顶级模块。import string
findpkg/string.py
不是因为它正在执行相对导入,而是因为它pkg/string.py
似乎是顶级模块string
。这不是标准库string
模块的事实没有出现。
To run the file as part of the pkg
package, you could do
要将文件作为pkg
包的一部分运行,您可以执行以下操作
python -m pkg.script
In this case, the pkg
directory will not be added to the path. However, the current directory will be added to the path.
在这种情况下,pkg
目录不会被添加到路径中。但是,当前目录将被添加到路径中。
You can also add some boilerplate to pkg/script.py
to make Python treat it as part of the pkg
package even when run as a file:
您还可以添加一些样板,pkg/script.py
使 Python 将其视为pkg
包的一部分,即使作为文件运行:
if __name__ == '__main__' and __package__ is None:
__package__ = 'pkg'
However, this won't affect sys.path
. You'll need some additional handling to remove the pkg
directory from the path, and if pkg
's parent directory isn't on the path, you'll need to stick that on the path too.
但是,这不会影响sys.path
. 您需要一些额外的处理来pkg
从路径中删除目录,如果pkg
的父目录不在路径上,您也需要将其粘贴在路径上。
回答by Bakuriu
The difference between absolute and relative imports come into play only when you import a module from a package and that module imports an other submodule from that package. See the difference:
只有当您从包中导入模块并且该模块从该包中导入另一个子模块时,绝对导入和相对导入之间的区别才会发挥作用。看到不同:
$ mkdir pkg
$ touch pkg/__init__.py
$ touch pkg/string.py
$ echo 'import string;print(string.ascii_uppercase)' > pkg/main1.py
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pkg/main1.py", line 1, in <module>
import string;print(string.ascii_uppercase)
AttributeError: 'module' object has no attribute 'ascii_uppercase'
>>>
$ echo 'from __future__ import absolute_import;import string;print(string.ascii_uppercase)' > pkg/main2.py
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>>
In particular:
特别是:
$ python2 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 1, in <module>
from __future__ import absolute_import;import string;print(string.ascii_uppercase)
AttributeError: 'module' object has no attribute 'ascii_uppercase'
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>>
$ python2 -m pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Note that python2 pkg/main2.py
has a different behaviour then launching python2
and then importing pkg.main2
(which is equivalent to using the -m
switch).
请注意,它python2 pkg/main2.py
具有不同的行为,然后启动python2
然后导入pkg.main2
(相当于使用-m
开关)。
If you ever want to run a submodule of a package always use the -m
switch which prevents the interpreter for chaining the sys.path
list and correctly handles the semantics of the submodule.
如果您想运行包的子模块,请始终使用-m
可防止解释器链接sys.path
列表并正确处理子模块语义的开关。
Also, I much prefer using explicit relative imports for package submodules since they provide more semantics and better error messages in case of failure.
此外,我更喜欢对包子模块使用显式相对导入,因为它们在失败时提供更多语义和更好的错误消息。