I found several options for doing this, before Antti posted his answer that Python 2 supports the Python 3 exec function syntax.
The first expression may also be a tuple of length 2 or 3. In this case, the optional parts must be omitted. The form exec(expr, globals)
is equivalent to exec expr in globals
, while the form exec(expr, globals, locals)
is equivalent to exec expr in globals, locals
. The tuple form of exec provides compatibility with Python 3, where exec is a function rather than a statement.
If you don't want to use that for some reason, here are all the other options I found.
Import Stubs
You can declare two different import stubs and import whichever one works with the current interpreter. This is based on what I saw in the PyDev source code.
Here's what you put in the main module:
try:
from exec_python2 import exec_code #@UnusedImport
except:
from exec_python3 import exec_code #@Reimport
Here's what you put in exec_python2.py
:
def exec_code(source, global_vars, local_vars):
exec source in global_vars, local_vars
Here's what you put in exec_python3.py
:
def exec_code(source, global_vars, local_vars):
exec(source, global_vars, local_vars)
Exec in Eval
Ned Batchelder posted a technique that wraps the exec
statement in a call to eval
so it won't cause a syntax error in Python 3. It's clever, but not clear.
# 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"
))
Six package
The six package is a compatibility library for writing code that will run under both Python 2 and Python 3. It has an exec_()
function that translates to both versions. I haven't tried it.