当前位置: 首页 > 面试题库 >

从__future__导入absolute_import实际起什么作用?

范嘉
2023-03-14
问题内容

我已经回答了有关Python中绝对导入的问题,我认为基于阅读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.mainpkg.string子模块。

考虑main.py模块中的代码。如果执行该语句会import string怎样?在Python
2.4和更早的版本,它会先看看在包的目录进行相对进口,发现包装/
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 (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中,您可以import使用from __future__ import absolute_import指令将的行为切换为绝对导入。这种绝对导入行为将在将来的版本(可能是Python 2.7)中成为默认设置。
一旦将绝对导入设置为默认设置,import string就将始终找到标准库的版本。

因此pkg/main2.py,我创建了,与main.py将来的import指令相同,但带有附加的将来import指令。现在看起来像这样:

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-
库版本绝对进口启用。而且,尽管警告绝对导入已计划成为“新的默认”行为,但无论使用还是不使用__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'

以及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__指令和绝对导入的内容相协调。

在我看来,这很容易通过以下方式进行解释(这是来自Python
2文档,但该语句在Python 3的同一文档中保持不变):

系统路径

(…)

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

那我想念什么呢?为什么该__future__声明似乎不按其要求行事?在这两部分文档之间以及所描述的行为与实际行为之间,这种矛盾的解决方案是什么?


问题答案:

变更日志的字眼太脏了。from __future__ import absolute_import并不关心某些东西是否是标准库的一部分,import string也不会总是为您提供启用绝对导入的标准库模块。

from __future__ import absolute_import表示如果您愿意import string,Python将始终寻找顶级string模块,而不是current_package.string。但是,它不会影响Python用于确定string模块文件的逻辑。当你做

python pkg/script.py

pkg/script.py看起来不像是Python软件包的一部分。按照正常步骤,将pkg目录添加到路径,并且.py目录中的所有文件pkg看起来都像顶级模块。import string发现pkg/string.py不是因为它正在执行相对导入,而是因为它pkg/string.py似乎是顶级模块string。这不是标准库string模块的事实并没有出现。

要将文件作为pkg软件包的一部分运行,您可以执行

python -m pkg.script

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

您还可以添加一些样板文件,pkg/script.py以使Pythonpkg即使在作为文件运行时也将其视为包的一部分:

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

但是,这不会影响sys.path。您需要进行一些其他处理才能pkg从路径中删除目录,如果pkg的父目录不在路径中,则也需要将其粘贴在路径中。



 类似资料:
  • 我已经回答了一个关于Python中的绝对导入的问题,我认为通过阅读Python2.5更改日志和附带的PEP我理解了这个问题。但是,在安装Python2.5并尝试创建一个从__future__import absolute_import中正确使用

  • 问题内容: 我知道这是一个内在的笑话,它会留下来(就像“ ”一样),但是它到底是做什么的呢? 问题答案: 与PEP 0401:BDFL退休有关 Barry指著名的Python开发人员Barry Warsaw。该基本取代了与运营商。

  • 问题内容: 我有时讨厌文档(当您是初学者时)的一件事是它实际上并没有用英语描述事物。有人介意为我翻译这份文档吗?我想知道这到底如何使黑客更难以插入字符。 http://php.net/manual/zh/function.mysql-real-escape- string.php 此外,如果是这种情况,黑客将如何尝试插入字符? 问题答案: 该函数在传递给该函数的字符串中的某些潜在危险字符之前添加转

  • 问题内容: 将变量标记为Java中的变量可确保每个线程都能看到最后写入该变量的值,而不是一些过时的值。我想知道这是如何实现的。JVM是否发出冲洗CPU现金或其他东西的特殊指令? 问题答案: 据我了解,它总是看起来好像写后缓存已被刷新,并且总是看起来好像是在读取时直接从内存中进行读取。这样做的结果是,一个线程将始终看到另一个线程的写入结果,并且(根据Java内存模型)永远不会看到缓存的值。但是,实际

  • 问题内容: 在有效的去它说,这些类型的进口平均副作用。我已经阅读了几个SO答案,但没有一个解释什么是。有人可以详细说明这个词吗? 问题答案: 当他们说“导入副作用”时,它们实际上是指静态使用的代码/功能。这意味着仅导入软件包将导致一些代码在应用程序启动时执行,从而使我的系统处于与未导入该软件包的状态不同的状态(例如示例中注册处理程序的代码,它也可能放下config文件,修改光盘上的资源等)。有效的

  • 问题内容: 在psql中,如果键入“从用户中选择*”,您将得到类似以下的内容: 在这种情况下,用户是什么? 问题答案: 在这种情况下,是内部保留的Postgres函数,它代表当前登录到数据库的用户。 该查询也可以写成: 哪个应该产生相同的结果。请注意,如果您想实际引用或创建一个名为的表,则必须使用引号或完全限定其所在的架构。例如: 可以工作,但是: 会产生错误。 这是其他系统信息功能的参考: ht