__future__导入在内部是如何工作的

4

我对__future__模块很感兴趣,特别是它可以改变Python语言中语句解析的方式。

最有趣的是,像这样做:

from __future__ import print_function

使您能够使用print(而不是像您期望的任何其他正常导入一样使用print_function)。
我已经彻底阅读了Python中的__future__用途、何时以及如何使用它以及它的工作原理,并特别注意到了其中的一行:

未来语句是一种指令,指示编译器应使用语法或语义在指定的Python未来版本中可用来编译特定模块。

我想知道是什么使这成为可能。特别是,像下面这样的东西如何实现:

from __future__ import division

可以在Python2中启用真正的除法,而不会像默认情况下那样进行截断。
from __future__ import barry_as_FLUFL

可以在Python3上启用<>语法(最有趣的是,你必须从"__future__"导入一个特性以实现向后兼容)。

无论如何,总结一下,我想知道当导入__future__或其产物时编译器如何理解和执行该指令。


1
因为它不是正常的导入。请参见https://docs.python.org/2/reference/simple_stmts.html#future - jonrsharpe
我应该把标题改成不鼓励那些注意力短暂的人进行负面评价。 - cs95
我觉得这个问题肯定有一些实质性的内容,无论我的意见价值如何。 - Ma0
@Ev.Kounis 那3个投反对票的人和1个关闭投票者可能会不同意,但无论如何,就像我说的...可能是因为最初标题不好导致的。 - cs95
@user2357112 你能详细说明一下吗?(也许在回答中)__future__导入将触发这些不同的标志,至少这是我所理解的。 - cs95
显示剩余3条评论
1个回答

7

from __future__ import print_function告诉解析器不将print视为关键字(而是将其保留为名称)。这样编译器就会将其视为函数而不是语句。

为了跟踪这一点,compiler结构体有一个c_future字段,保存一个PyFutureFeatures对象,用于跟踪已启用的未来指令。解析器和编译器的各个部分都会检查标志并改变行为。

这主要在future.c源文件中处理,其中有一个future_parse()函数,它检查具有模块参数设置为__future__import from AST对象,并根据找到的内容设置标志。

例如,对于barry_as_FLUFL特性,解析器拒绝使用!=作为语法,但接受<>代替
if (type == NOTEQUAL) {
    if (!(ps->p_flags & CO_FUTURE_BARRY_AS_BDFL) &&
                    strcmp(str, "!=")) {
        PyObject_FREE(str);
        err_ret->error = E_SYNTAX;
        break;
    }
    else if ((ps->p_flags & CO_FUTURE_BARRY_AS_BDFL) &&
                    strcmp(str, "<>")) {
        PyObject_FREE(str);
        err_ret->text = "with Barry as BDFL, use '<>' "
                        "instead of '!='";
        err_ret->error = E_SYNTAX;
        break;
    }
}

你可以通过在 compile.h 中列出的 FUTURE_* 标志进行 grepping 查找其他示例。
请注意,有一个 __future__ Python 模块,但它并不直接参与代码的解析和编译; 它只是为了让 Python 代码轻松访问关于指令的元数据(包括传递给 compile() 函数flags 参数的位字段值),仅此而已。

我已经知道这个了。我想知道它在底层是如何工作的...... 这就是我提出这个问题的目的。 - cs95
@cᴏʟᴅsᴘᴇᴇᴅ:这个问题有点宽泛,但我会尽力填写。 - Martijn Pieters
我觉得巴里最有趣的地方在于他必须来自__future__,而不是像__past__这样更合理的东西。感谢你一如既往的出色回答。 - cs95

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接