Ich verwende die Anweisung exec in einem Python 2-Code und versuche, diesen Code sowohl mit Python 2 als auch mit Python 3 kompatibel zu machen. In Python 3 hat sich exec jedoch von einer Anweisung geändert in eine Funktion. Ist es möglich, Code zu schreiben, der sowohl mit Python 2 als auch mit Python 3 kompatibel ist? Ich habe über Python 2 und Python 3 Dual Development gelesen, bin aber an spezifischen Lösungen für {{X2 interessiert }} Anweisungs- / Funktionsänderungen.

Mir ist klar, dass exec generell nicht empfohlen wird, aber ich erstelle ein Eclipse-Plugin, das Live-Codierung auf PyDev implementiert. Weitere Informationen finden Sie auf der Projektseite.

8
Don Kirkby 10 Okt. 2012 im 02:17

2 Antworten

Ich musste dies tun, ich konnte nicht sechs verwenden, und meine Version von Python unterstützt die Methode von @ Antti nicht, da ich sie in einer verschachtelten Funktion mit freien Variablen verwendet habe. Ich wollte auch keine unnötigen Importe. Folgendes habe ich mir ausgedacht. Dies muss wahrscheinlich im Modul sein, nicht in einer Methode:

try:
  # Try Python2.
  _exec_impls = {
    0: compile('exec code', '<python2>', 'exec'),
    1: compile('exec code in _vars[0]', '<python2>', 'exec'),
    2: compile('exec code in _vars[0], _vars[1]', '<python2>', 'exec'),
  }

  def _exec(code, *vars):
    impl = _exec_impls.get(len(vars))
    if not impl:
      raise TypeError('_exec expected at most 3 arguments, got %s' % (len(vars) + 1))
    return eval(impl, { 'code': code, '_vars': vars })

except Exception as e:
  # Wrap Python 3.
  _exec = eval('exec')

Danach funktioniert _exec wie die Python3-Version. Sie können ihm entweder eine Zeichenfolge geben oder compile() durchlaufen. Es wird nicht die Globalen oder Einheimischen bekommen, die Sie wahrscheinlich wollen, also geben Sie sie weiter:

def print_arg(arg):
  def do_print():
    print(arg)
  _exec('do_print(); do_print(); do_print()', globals(), locals())

print_arg(7)  # Prints '7'

Oder nicht. Ich bin ein StackOverflow-Beitrag, kein Polizist.

Updates:

Warum benutzt du nicht einfach eval()? eval() erwartet einen Ausdruck , während exec() Anweisungen erwartet. Wenn Sie nur einen Ausdruck haben, spielt es keine Rolle, was Sie verwenden, da alle gültigen Ausdrücke gültige Anweisungen sind, aber die Umkehrung ist nicht wahr. Nur eine Methode auszuführen ist ein Ausdruck, auch wenn sie nichts zurückgibt. Es wird ein implizites None zurückgegeben.

Dies wird demonstriert, indem versucht wird, pass zu bewerten, was eine Aussage ist:

>>> exec('pass')
>>> eval('pass')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    pass
       ^
SyntaxError: unexpected EOF while parsing
1
Hounshell 29 Dez. 2016 im 18:24

Ich habe mehrere Optionen dafür gefunden, bevor Antti seine Antwort veröffentlichte, dass Python 2 Python 3 Exec-Funktionssyntax.

Der erste Ausdruck kann auch ein Tupel der Länge 2 oder 3 sein. In diesem Fall müssen die optionalen Teile weggelassen werden. Die Form exec(expr, globals) entspricht exec expr in globals, während die Form exec(expr, globals, locals) exec expr in globals, locals entspricht. Die Tupelform von exec bietet Kompatibilität mit Python 3, wobei exec eher eine Funktion als eine Anweisung ist.

Wenn Sie das aus irgendeinem Grund nicht verwenden möchten, finden Sie hier alle anderen Optionen, die ich gefunden habe.

Stubs importieren

Sie können zwei verschiedene Importstubs deklarieren und importieren, je nachdem, welcher mit dem aktuellen Interpreter funktioniert. Dies basiert auf dem, was ich im PyDev-Quellcode gesehen habe.

Folgendes haben Sie in das Hauptmodul eingefügt:

try:
    from exec_python2 import exec_code #@UnusedImport
except:
    from exec_python3 import exec_code #@Reimport

Folgendes haben Sie in exec_python2.py eingegeben:

def exec_code(source, global_vars, local_vars):
    exec source in global_vars, local_vars

Folgendes haben Sie in exec_python3.py eingegeben:

def exec_code(source, global_vars, local_vars):
    exec(source, global_vars, local_vars)

Exec in Eval

Ned Batchelder hat eine Technik veröffentlicht, die die Anweisung exec in einen Aufruf von einschließt eval, damit in Python 3 kein Syntaxfehler auftritt. Es ist clever, aber nicht klar.

# 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"
    ))

Sechs Pakete

Das Six-Paket ist eine Kompatibilitätsbibliothek zum Schreiben von Code, der sowohl unter Python 2 als auch unter Python 3 ausgeführt wird. Es verfügt über eine exec_() -Funktion, die in beide Versionen übersetzt wird. Ich habe es nicht versucht.

6
Community 23 Mai 2017 im 12:02