web-dev-qa-db-de.com

Wie führe ich einen String aus, der Python-Code in Python enthält?

Wie führe ich einen String aus, der Python-Code in Python enthält?

270
hekevintran

Im Beispiel wird ein String mit der Funktion exec als Code ausgeführt.

import sys
import StringIO

# create file-like string to capture output
codeOut = StringIO.StringIO()
codeErr = StringIO.StringIO()

code = """
def f(x):
    x = x + 1
    return x

print 'This is my output.'
"""

# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr

exec code

# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__

print f(4)

s = codeErr.getvalue()

print "error:\n%s\n" % s

s = codeOut.getvalue()

print "output:\n%s" % s

codeOut.close()
codeErr.close()
57
hekevintran

Verwenden Sie für Anweisungen exec(string) (Python 2/3) oder exec string (Python 2):

>>> mycode = 'print "hello world"'
>>> exec(mycode)
Hello world

Wenn Sie den Wert eines Ausdrucks benötigen, verwenden Sie eval(string) :

>>> x = eval("2+2")
>>> x
4

Der erste Schritt sollte jedoch sein, sich zu fragen, ob Sie wirklich etwas brauchen. Das Ausführen von Code sollte im Allgemeinen die Position des letzten Auswegs sein: Er ist langsam, hässlich und gefährlich, wenn er vom Benutzer eingegebener Code enthalten kann. Sie sollten immer zuerst nach Alternativen suchen, z. B. mit Funktionen höherer Ordnung, um zu sehen, ob diese Ihren Anforderungen besser entsprechen.

262
Brian

Denken Sie daran, dass ab Version 3 exec eine Funktion ist!
Verwenden Sie also immer exec(mystring) anstelle von exec mystring.

19
bheks

eval und exec sind die richtige Lösung und können auf sicherere Weise verwendet werden.

Wie in Python's Referenzhandbuch erläutert und in dieses Lernprogramm klar erläutert, benötigen die Funktionen eval und exec zwei zusätzliche Parameter, mit denen ein Benutzer angeben kann, welche globalen und lokalen Funktionen und Variablen verfügbar sind.

Zum Beispiel:

public_variable = 10

private_variable = 2

def public_function():
    return "public information"

def private_function():
    return "super sensitive information"

# make a list of safe functions
safe_list = ['public_variable', 'public_function']
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
# add any needed builtins back in
safe_dict['len'] = len

>>> eval("public_variable+2", {"__builtins__" : None }, safe_dict)
12

>>> eval("private_variable+2", {"__builtins__" : None }, safe_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'private_variable' is not defined

>>> exec("print \"'%s' has %i characters\" % (public_function(), len(public_function()))", {"__builtins__" : None}, safe_dict)
'public information' has 18 characters

>>> exec("print \"'%s' has %i characters\" % (private_function(), len(private_function()))", {"__builtins__" : None}, safe_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'private_function' is not defined

Im Wesentlichen definieren Sie den Namespace, in dem der Code ausgeführt wird.

18
alan

eval() ist nur für Ausdrücke, während eval('x+1') funktioniert, eval('x=1') zum Beispiel nicht funktioniert. In diesem Fall ist es besser, exec zu verwenden, oder noch besser: Versuchen Sie, eine bessere Lösung zu finden :)

11
LGB

Sie führen die Ausführung von Code mithilfe von exec wie bei der folgenden IDLE-Sitzung aus:

>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']

4
9
gus

Vermeiden Sie exec und eval

Die Verwendung von exec und eval in Python ist äußerst verpönt.

Es gibt bessere Alternativen

Von der obersten Antwort (Hervorhebung meines):

Verwenden Sie für Anweisungen exec.

Wenn Sie den Wert eines Ausdrucks benötigen, verwenden Sie eval.

Der erste Schritt sollte jedoch sein, sich zu fragen, ob Sie wirklich etwas brauchen. Ausführungscode sollte im Allgemeinen die Position des letzten Auswegs sein: Es ist langsam, hässlich und gefährlich, wenn er vom Benutzer eingegebenen Code enthalten kann. Sie sollten immer zuerst alternatives betrachten, z. B. Funktionen höherer Ordnung, um zu sehen, ob diese Ihren Anforderungen besser entsprechen.

Von Alternativen zu exec/eval?

setze und erhalte Werte von Variablen mit den Namen in Strings

[Während eval] funktionieren würde, wird generell davon abgeraten, Variablennamen zu verwenden, die eine Bedeutung für das Programm selbst haben.

Verwenden Sie stattdessen lieber ein Dikt.

Es ist nicht idiomatisch

Von http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (Hervorhebung meines)

Python ist kein PHP

Versuchen Sie nicht, Python-Idiome zu umgehen, da eine andere Sprache dies anders macht. Namespaces sind aus einem bestimmten Grund in Python und , nur weil es das Werkzeug exec gibt, bedeutet dies nicht, dass Sie dieses Werkzeug verwenden sollten.

Es ist gefährlich

Von http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (Hervorhebung meines)

Eval ist also nicht sicher, auch wenn Sie alle Globals und die Builtins entfernen!

Das Problem bei all diesen Versuchen, eval () zu schützen, ist, dass es sich um schwarze Listen handelt. Sie entfernen explizit Dinge, die gefährlich sein könnten. Das ist eine Niederlage, weil wenn nur ein Element von der Liste übrig ist, können Sie das System angreifen.

Kann also eval sicher gemacht werden? Schwer zu sagen. Meine beste Vermutung ist an diesem Punkt, dass Sie keinen Schaden anrichten können, wenn Sie keine doppelten Unterstriche verwenden können. Wenn Sie also eine Zeichenfolge mit doppelten Unterstrichen ausschließen, sind Sie sicher. Könnte sein...

Es ist schwer zu lesen und zu verstehen

Von http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (Hervorhebung meines):

Zunächst macht es exec für Menschen schwieriger, Ihren Code zu lesen. Um herauszufinden, was passiert, muss ich nicht nur Ihren Code lesen, Ich muss Ihren Code lesen, herausfinden, welche Zeichenfolge er erzeugen wird, und dann den virtuellen Code lesen. Wenn Sie also in einem Team arbeiten, Open-Source-Software veröffentlichen oder an einem anderen Ort wie StackOverflow um Hilfe bitten, ist es für andere schwieriger, Ihnen zu helfen. Und wenn Sie die Möglichkeit haben, diesen Code in 6 Monaten zu debuggen oder zu erweitern, wird es für Sie direkt schwieriger.

9
Caridorc

Check out Bewertung :

x = 1
print eval('x+1')
->2
4
ryeguy

Die logischste Lösung wäre die Verwendung der integrierten Funktion eval () . Eine andere Lösung besteht darin, diesen String in eine temporäre Python-Datei zu schreiben und auszuführen. 

3
John T

Verwenden Sie eval .

2

Es ist erwähnenswert, dass der Bruder von 'exec auch execfile heißt, wenn Sie eine python Datei aufrufen möchten. Das ist manchmal gut, wenn Sie in arbeiten ein Paket von Drittanbietern, in dem schreckliche IDEs enthalten sind und das Sie außerhalb des Pakets codieren möchten.

Beispiel:

execfile('/path/to/source.py)'

oder:

exec(open("/path/to/source.py").read())

2
user1767754

Wie die anderen erwähnt haben, ist es "exec" .. 

falls Ihr Code jedoch Variablen enthält, können Sie "global" verwenden, um darauf zuzugreifen, und verhindern, dass der Compiler den folgenden Fehler ausgibt:

NameError: Name 'p_variable' ist nicht definiert

exec('p_variable = [1,2,3,4]')
global p_variable
print(p_variable)
1
Ghanem

Ok .. Ich weiß, das ist nicht genau eine Antwort, aber möglicherweise eine Notiz für Leute, die sich das so ansehen, wie ich es war. Ich wollte spezifischen Code für verschiedene Benutzer/Kunden ausführen, aber auch die Exec/Eval vermeiden. Ich habe zunächst versucht, den Code für jeden Benutzer in einer Datenbank zu speichern und dies zu tun.

Am Ende habe ich die Dateien im Dateisystem in einem 'customer_filters'-Ordner erstellt und das' imp'-Modul verwendet. Wenn für diesen Kunden kein Filter angewendet wurde, wurde er einfach weitergeführt

import imp


def get_customer_module(customerName='default', name='filter'):
    lm = None
    try:
        module_name = customerName+"_"+name;
        m = imp.find_module(module_name, ['customer_filters'])
        lm = imp.load_module(module_name, m[0], m[1], m[2])
    except:
        ''
        #ignore, if no module is found, 
    return lm

m = get_customer_module(customerName, "filter")
if m is not None:
    m.apply_address_filter(myobj)

customerName = "jj" führt dann apply_address_filter aus der Datei customer_filters\jj_filter.py aus

0
Brian