Ich versuche gerade eine Python (3.4.4) GUI mit tkinter zu programmieren, die es erlauben sollte, eine beliebige Funktion an einige Datenpunkte anzupassen. Um einfach zu beginnen, möchte ich einige Eingabefunktionen erstellen und auswerten. Später möchte ich es plotten und passen curve_fit
von scipy
.Alternative zu exec
Um dies zu tun, möchte ich eine dynamische (Fitting) -Funktion aus einem Benutzer-Eingabe-String erstellen. Ich fand und las über exec
, aber Leute sagen, dass (1) es nicht sicher zu verwenden ist und (2) es gibt immer eine bessere Alternative (z. B. here und an vielen anderen Orten). Also, ich fragte mich, was wäre die Alternative in diesem Fall?
Hier einige Beispiel-Code mit zwei verschachtelte Funktionen, die funktioniert, aber es ist nicht dynamisch:
def buttonfit_press():
def f(x):
return x+1
return f
print(buttonfit_press()(4))
Und hier ist ein Code, der zu NameError: name 'f' is not defined
gibt, bevor ich auch verwenden xval starten:
def buttonfit_press2(xval):
actfitfunc = "f(x)=x+1"
execstr = "def {}:\n return {}\n".format(actfitfunc.split("=")[0], actfitfunc.split("=")[1])
exec(execstr)
return f
print(buttonfit_press2(4))
Ein alternativer Ansatz mit types.FunctionType
hier diskutiert (10303248) war auch nicht erfolgreich ...
S o, meine Frage ist: Gibt es eine gute Alternative, die ich für dieses Szenario verwenden könnte? Oder wenn nicht, wie kann ich den Code mit exec
laufen lassen?
Ich hoffe, es ist verständlich und nicht zu vage. Vielen Dank im Voraus für Ihre Ideen und Anregungen.
@ Gábor Erdos:
Entweder verstehe ich nicht oder ich nicht zustimmen. Wenn ich das gleiche Segment im mainloop kodieren, erkennt es f
und ich kann das Code-Segment von execstr
ausführen:
actfitfunc = "f(x)=x+1"
execstr = "def {}:\n return {}\n".format(actfitfunc.split("=")[0], actfitfunc.split("=")[1])
exec(execstr)
print(f(4))
>>> 5
@ Łukasz Rogalski:
Printing execstr
scheint gut zu mir:
Einrückungsfehler ist aufgrund meines Editors unwahrscheinlich, aber ich habe es überprüft - es ist in Ordnung. my_locals
Einführung, es in exec
und Druck in danach Aufruf zeigt:
{'f': <function f at 0x000000000348D8C8>}
Allerdings habe ich immer noch NameError: name 'f' is not defined
bekommen.
@ user3691475:
Ihr Beispiel ist sehr ähnlich wie mein erstes Beispiel. Aber das ist in meinem Verständnis nicht "dynamisch", d.h. man kann die Ausgabe der Funktion nicht ändern, während der Code läuft.
@Dunes:
Ich denke, dies in die richtige Richtung geht, danke.Allerdings verstehe ich noch nicht, wie ich diese Funktion im nächsten Schritt bewerten und nutzen kann. Was ich meine ist: Um es anpassen zu können, muss ich passende Variablen (d. H. a
in f(x)=a*x+b
) extrahieren oder die Funktion bei verschiedenen x-Werten auswerten (d. H. print(f(3.14))
).
@ GáborErdős technisch ist es, da exec implizit Verweise auf 'Globals() übergeben wird' und 'Einheimischen()' und Eingabeargumente, und sie werden mutiert werden. –
@nostradamus Ihr Code sollte gut funktionieren. Ist Ihre Einrückung korrekt? Kannst du folgendes ausführen: 'my_locals = {}; exec (execstr, globals(), my_locals) und zeige danach, was in 'my_locals' gespeichert ist? Eine Überprüfung der Gesundheit durch Drucken von "execstr" wird ebenfalls nicht schaden. –