from __future__ import absolute_import 实际上是做什么的? [英] What does from __future__ import absolute_import actually do?

查看:59
本文介绍了from __future__ import absolute_import 实际上是做什么的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有回答一个关于 Python 中绝对导入的问题,我认为我根据阅读Python 2.5 变更日志 和随附的 PEP.但是,在安装 Python 2.5 并尝试制作一个正确使用 from __future__ import absolute_import 的示例后,我意识到事情并不是那么清楚.

I have answered a question regarding absolute imports in Python, which I thought I understood based on reading the Python 2.5 changelog and 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.

直接从上面链接的更改日志中,这个语句准确地总结了我对绝对导入更改的理解:

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

这定义了一个名为 pkg 的包,其中包含 pkg.mainpkg.string 子模块.

This defines a package named pkg containing the pkg.main and pkg.string submodules.

考虑 main.py 模块中的代码.如果它执行语句 import string 会发生什么?在 Python 2.4 及更早版本中,它将首先在包目录中查找以执行相对导入,找到 pkg/string.py,将该文件的内容作为 pkg.string 模块导入,然后该模块绑定到 pkg.main 模块命名空间中的名称 "string".

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 the pkg.string module, and that module is bound to the name "string" in the pkg.main module's namespace.

所以我创建了这个确切的目录结构:

So I created this exact directory structure:

$ ls -R
.:
pkg/

./pkg:
__init__.py  main.py  string.py

__init__.pystring.py 为空.main.py 包含以下代码:

__init__.py and string.py are empty. main.py contains the following code:

import string
print string.ascii_uppercase

正如预期的那样,在 Python 2.5 中运行它会失败并返回 AttributeError:

As expected, running this with Python 2.5 fails with an 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 更改日志中,我们发现了这一点(强调):

However, further along in the 2.5 changelog, we find this (emphasis added):

在 Python 2.5 中,您可以使用 from __future__ import absolute_import 指令将 import 的行为切换为绝对导入.这种绝对导入行为将成为未来版本(可能是 Python 2.7)的默认设置.一旦绝对导入成为默认值,import string 将始终找到标准库的版本.

In Python 2.5, you can switch import's behaviour to absolute imports using a from __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.

我因此创建了 pkg/main2.py,与 main.py 相同,但具有额外的未来导入指令.现在看起来像这样:

I thus created pkg/main2.py, identical to main.py but with the additional future import directive. It now looks like this:

from __future__ import absolute_import
import string
print string.ascii_uppercase

使用 Python 2.5 运行此程序,但是...失败并显示 AttributeError:

Running this with Python 2.5, however... fails with an 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__ 指令:

This pretty flatly contradicts the statement that import string will always find 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:

$ 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 语句在两个文件中都已更改):

as well as Python 3.5, with or without (assuming the print statement is changed in both files):

$ 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 发出导入,我有 cdpkg 并直接从 REPL 运行导入.这些变化(或它们的组合)都没有改变上述结果.我无法将其与我所了解的关于 __future__ 指令和绝对导入的内容相协调.


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.

在我看来,这很容易通过以下内容来解释(这是来自 Python 2 文档,但此语句在 Python 3 的相同文档中保持不变):

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):

(...)

在程序启动时初始化,此列表的第一项 path[0] 是包含用于调用 Python 解释器的脚本的目录.如果脚本目录不可用(例如,如果交互式调用解释器或从标准输入读取脚本),path[0] 是空字符串,指示 Python 进行搜索首先是当前目录中的模块.

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.

那我错过了什么?为什么 __future__ 语句看起来不像它所说的那样,这两个文档部分之间以及描述和实际行为之间的这种矛盾的解决方案是什么?

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?

推荐答案

变更日志措辞草率.from __future__ import absolute_import 不关心某些东西是否是标准库的一部分,并且 import string 不会总是为您提供绝对导入的标准库模块.

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,Python 会一直寻找顶级的string 模块,而不是<代码>current_package.string.但是,它不会影响 Python 用来决定哪个文件是 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

python pkg/script.py

pkg/script.py 看起来不像 Python 包的一部分.按照正常的流程,在路径中添加pkg目录,pkg目录下的所有.py文件看起来都是顶级模块.import string 找到 pkg/string.py 不是因为它进行了相对导入,而是因为 pkg/string.py 似乎是最重要的 -级别模块 string.这不是标准库 string 模块的事实没有出现.

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 包的一部分运行,您可以这样做

To run the file as part of the pkg package, you could do

python -m pkg.script

在这种情况下,pkg 目录将不会添加到路径中.但是,当前目录将被添加到路径中.

In this case, the pkg directory will not be added to the path. However, the current directory will be added to the path.

您还可以向 pkg/script.py 添加一些样板文件,使 Python 将其视为 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:

if __name__ == '__main__' and __package__ is None:
    __package__ = 'pkg'

但是,这不会影响 sys.path.你需要一些额外的处理来从路径中删除 pkg 目录,如果 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.

这篇关于from __future__ import absolute_import 实际上是做什么的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆