You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

__future__ 导入与 eval、exec、compile 的交互机制探究

future 导入与 eval/exec/compile 的交互细节

咱们直接结合Python 2的实际案例来拆解这个问题,逻辑其实挺清晰的:

模块级的 future 导入会全局覆盖 eval/exec 的默认行为

当你在模块顶部导入__future__的特性时,这个设定会作用于整个模块的代码环境——包括通过eval()和exec()执行的代码片段。比如你给出的这段代码:

from __future__ import print_function
print(1, end='!')
eval(r"print(2, end='!')")
exec r"print(3, end='!')"

运行后输出1!2!3!,这说明不管是模块内直接写的print,还是eval/exec里的print,都用了print_function带来的函数式调用方式,而不是Python 2默认的语句式print。

本质原因是__future__导入会修改当前模块的编译标志,而eval和exec默认会继承当前环境的编译标志,自然就跟着模块的设定走了。

exec 内部的 future 导入只对自身代码块生效

如果在exec的代码块里单独导入__future__特性,这个改动只会局限在这个代码块内部,不会影响外部的代码环境。举个例子:

# 外部还是Python 2默认的print语句
print 1  # 输出: 1

exec r"""
from __future__ import print_function
print(2, end='!')  # 这里用的是函数式print
"""

# 外部依然用语句式print,完全不受exec内的导入影响
print 3  # 输出: 3

执行后的输出是:

1
2!3

这是因为exec在处理内部代码时,会为这段代码单独创建一个编译上下文,内部的__future__导入只会修改这个局部上下文的编译标志,不会波及外部模块的设定。

额外补充:compile() 可以手动控制编译标志

如果你需要更精细的控制,可以用compile()函数手动指定编译标志,甚至绕过模块级的__future__设定。比如:

from __future__ import print_function
# 强制使用Python 2默认的print语句编译代码片段
code = compile("print 4", "<string>", "exec", dont_inherit=True)
exec(code)  # 输出: 4

这里的dont_inherit=True参数告诉编译器:不要继承当前模块的编译标志,所以这段代码即使在导入了print_function的模块里,依然会用旧的语句式print。


内容的提问来源于stack exchange,提问作者Aran-Fey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:16:19