是否可以调用exec以使其与Python 3和Python 2兼容?

Don*_*kby 7 python python-2.7 python-3.x

exec在一些Python 2代码中使用该语句,并且我试图使该代码与Python 2和Python 3兼容,但是在Python 3中,exec已经从语句变为函数.是否可以编写与Python 2和3兼容的代码?我已经阅读了Python 2和Python 3双重开发,但我对exec语句/函数更改的特定解决方案感兴趣.

我意识到这exec通常是气馁的,但我正在构建一个Eclipse插件,它在PyDev之上实现了实时编码.有关详细信息,请参阅项目页面.

Ant*_*ala 12

一些Python移植指南exec 错误:

如果你需要传入全局或本地词典,你需要定义一个带有两个不同实现的自定义函数,一个用于Python 2,另一个用于Python 3.通常six包括一个很好的实现exec_().

将Python 2代码移植到Python 3(*)中不需要这样的自定义函数.你可以做exec(code),exec(code, globs)而且exec(code, globs, locs)在Python 2,和它的作品.

Python已经永远接受的Python 3兼容的"语法"的exec,只要是exec存在的.这样做的原因是Python 2和Python 1(?!)有一个hack 与Python 0.9.8 保持向后兼容,这exec是一个函数.现在,如果exec传递一个2元组,则将其解释为(code, globals),如果是3元组,则将其解释为(code, globals, locals).是的,exec_insix是不必要的复杂.

从而,

exec(source, global_vars, local_vars)
Run Code Online (Sandbox Code Playgroud)

保证在CPython 0.9.9,1.x,2.x,3.x中以相同的方式工作; 我还验证了它适用于Jython 2.5.2,PyPy 2.3.1(Python 2.7.6)和IronPython 2.6.1:

Jython 2.5.2 (Release_2_5_2:7206, Mar 2 2011, 23:12:06) 
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_25
Type "help", "copyright", "credits" or "license" for more information.
>>> exec('print a', globals(), {'a':42})
42
Run Code Online (Sandbox Code Playgroud)

*)存在细微差别,因此并非所有Python 3代码都适用于Python 2,即

同样,边缘情况下的解决方案可能是放弃使用exec和使用eval(eval可用于执行compileexec模式下编译的字节码):

def print_arg(arg):
    def do_print():
        print(arg)

    eval(compile('do_print(); print("it really works")', '<string>', 'exec'))
Run Code Online (Sandbox Code Playgroud)

我已经写就的内部更详细的解答exec,evalcompile什么是EVAL,EXEC之间的差异,在Python编写?


Don*_*kby 6

在Antti发布他的回答说Python 2支持Python 3 exec函数语法之前,我找到了几个选项.

第一个表达式也可以是长度为2或3的元组.在这种情况下,必须省略可选部分.表格exec(expr, globals)相当于exec expr in globals,而形式exec(expr, globals, locals)相当于exec expr in globals, locals.exec的元组形式提供与Python 3的兼容性,其中exec是函数而不是语句.

如果由于某种原因你不想使用它,这里是我找到的所有其他选项.

导入存根

您可以声明两个不同的导入存根,并导入与当前解释器一起使用的任何导入存根.这基于我在PyDev源代码中看到的内容.

这是你放在主模块中的内容:

try:
    from exec_python2 import exec_code #@UnusedImport
except:
    from exec_python3 import exec_code #@Reimport
Run Code Online (Sandbox Code Playgroud)

这是你输入的内容exec_python2.py:

def exec_code(source, global_vars, local_vars):
    exec source in global_vars, local_vars
Run Code Online (Sandbox Code Playgroud)

这是你输入的内容exec_python3.py:

def exec_code(source, global_vars, local_vars):
    exec(source, global_vars, local_vars)
Run Code Online (Sandbox Code Playgroud)

执行Eval

Ned Batchelder发布了一种技术,可以exec在调用中包装语句,eval因此它不会在Python 3中导致语法错误.它很聪明,但不清楚.

# Exec is a statement in Py2, a function in Py3

if sys.hexversion > 0x03000000:
    def exec_function(source, filename, global_map):
        """A wrapper around exec()."""
        exec(compile(source, filename, "exec"), global_map)
else:
    # OK, this is pretty gross.  In Py2, exec was a statement, but that will
    # be a syntax error if we try to put it in a Py3 file, even if it isn't
    # executed.  So hide it inside an evaluated string literal instead.
    eval(compile("""\
def exec_function(source, filename, global_map):
    exec compile(source, filename, "exec") in global_map
""",
    "<exec_function>", "exec"
    ))
Run Code Online (Sandbox Code Playgroud)

六包

6包是用于编写代码的兼容性库,都将Python 2和Python 3的下运行它有一个exec_()功能,这相当于两个版本.我没试过.