webentwicklung-frage-antwort-db.com.de

Wie erhalte ich den Rückgabewert, wenn ich Python exec für das Code-Objekt einer Funktion verwende?

Zu Testzwecken möchte ich eine in einer anderen Funktion definierte Funktion direkt ausführen.

Ich kann durch den Code (func_code) der übergeordneten Funktion zum Codeobjekt der untergeordneten Funktion gelangen, aber wenn ich es ausführe, erhalte ich keinen Rückgabewert.

Gibt es eine Möglichkeit, den Rückgabewert aus dem ausgeführten Code zu erhalten?

15
user2433423

Ja, Sie müssen die Zuweisung innerhalb der exec-Anweisung haben:

>>> def foo():
...     return 5
...
>>> exec("a = foo()")
>>> a
5

Dies ist wahrscheinlich für Ihren Fall nicht relevant, da es in kontrollierten Tests verwendet wird, aber Seien Sie vorsichtig bei der Verwendung von exec mit benutzerdefinierten Eingaben.  

12
wnnmaw

So etwas kann funktionieren:

def outer():
    def inner(i):
        return i + 10


for f in outer.func_code.co_consts:
    if getattr(f, 'co_name', None) == 'inner':

        inner = type(outer)(f, globals())

        # can also use `types` module for readability:
        # inner = types.FunctionType(f, globals())

        print inner(42) # 52

Die Idee ist, das Code-Objekt aus der inneren Funktion zu extrahieren und darauf basierend eine neue Funktion zu erstellen.

Zusätzliche Arbeit ist erforderlich, wenn eine innere Funktion freie Variablen enthalten kann. Sie müssen sie ebenfalls extrahieren und im letzten Argument (closure) an den Funktionskonstruktor übergeben.

1
georg

Während dies die hässlichste Bestie ist, die die Menschheit je gesehen hat, können Sie dies tun, indem Sie eine globale Variable in Ihrem Exec-Aufruf verwenden:

def my_exec(code):
    exec('global i; i = %s' % code)
    global i
    return i

Dies ist ein Missbrauch globaler Variablen, um Ihre Daten über die Grenze zu bringen.

>>> my_exec('1 + 2')
3

Es ist unnötig zu erwähnen, dass Sie niemals / Benutzereingaben für die Eingabe dieser Funktion zulassen sollten, da dies ein extremes Sicherheitsrisiko darstellt.

0
devsnd