Seite 1 von 1

Lambda Funktion

Verfasst: Samstag 4. Dezember 2021, 08:32
von th_goebi
Hallo Python-Forum Freunde,

ich habe für eine Routine (in COBYLA) folgende lambda-Funktionen definiert:

con[1] = lambda x: x[1] - x[0]--1

con[2] = lambda x : x[2] - x[0] -1

con[3] = lambda x : x[3] -x[0] -1

usw. bis:

con[n] = lambda x : x[n] - x[0] -1


Mein Programm funktioniert damit.

Kann ich die n Funktionen auch mithilfe einer "for i in range (1,n): ..." Schleife vereinfacht programmieren? Ich bekomme das nicht hin.
Danke für eure Hilfe.

Re: Lambda Funktion

Verfasst: Samstag 4. Dezember 2021, 10:16
von __blackjack__
@th_goebi: Das Problem das Du haben dürftest ist das Namen erst aufgelöst werden wenn der Code der Ausdruck ausgewertet wird. Also das `i` bei dem ``x[ i ]`` hat dann bei allen Funktionen den letzten Wert den `i` in der ``for``-Schleife hatte. Oder gar einen anderen wenn `i` danach noch einmal durch weiteren Code verändert wurde.

Es gibt zwei übliche Arten das zu lösen: Werte für Defaultargumente werden nur einmal ausgewertet, nämlich zum Zeitpunkt der Definition von Funktionen. Und `functools.partial()`.

Ungetestet:

Code: Alles auswählen

    for i in range(1, n + 1):
        con[i] = lambda xs, i=i: xs[i] - xs[0] - 1

    # oder

    for i in range(1, n + 1):
        con[i] = partial((lambda i, xs: xs[i] - xs[0] - 1), i)

Re: Lambda Funktion

Verfasst: Samstag 4. Dezember 2021, 10:45
von narpfel
Da die Funktionen sich alle in genau einem Wert unterscheiden, würde ich da nur eine Funktion schreiben und in `con` jeweils nur das `i` speichern:

Code: Alles auswählen

def f(x, i):
    return x[i] - x[0] - 1

con = range(1, n + 1)
...
do_something_with(f(x, con[value]))

Re: Lambda Funktion

Verfasst: Samstag 4. Dezember 2021, 12:27
von __blackjack__
@narpfel: Ich habe mir COBYLA nicht näher angeschaut, aber bei solchen „constraints solving/optimization“-Bibliotheken muss man die Constraints oft in Form von Funktionen angeben. Der Solver entscheidet dann wann er welche Funktion aufruft.

Re: Lambda Funktion

Verfasst: Samstag 4. Dezember 2021, 12:49
von th_goebi
Vielen Dank für eure Antworten. Es funktioniert leider nicht, da er in con und x jeweils "i" reinschreibt und nicht den aktuellen Wert (1,2, ... ,n) der Schleifenvariablen. Die COBYLA-Routine braucht aber die con's so, wie ich es in meinem Post angegeben habe, sonst stürzt das Programm ab. Gibt es eventuell noch einen anderen Weg?

Re: Lambda Funktion

Verfasst: Samstag 4. Dezember 2021, 13:23
von __deets__
Was genau hast du jetzt versucht? Der Ansatz von __blackjack__ sollte eigentlich aequivalent sein.

Code: Alles auswählen

con = []
con.append(lambda x: x[1] - x[0] - 1)
con.append(lambda x: x[2] - x[0] - 1)
con.append(lambda x: x[3] - x[0] - 1)

bound_con = []
for i in range(1, 4):
    bound_con.append(lambda x, i=i: x[i] - x[0] - 1)

x = list(range(100))

for manual, generated in zip(con, bound_con):
    print(manual(x), generated(x))
Wenn er das nicht ist, dann muss da noch etwas anderes vor sich gehen. Hast du Fehlermeldungen?

Re: Lambda Funktion

Verfasst: Samstag 4. Dezember 2021, 13:26
von __deets__
Nachtrag: falls das Paket irgendwie durch Introspektion versucht, etwas ueber die gegebenen Funktionen rauszufinden, dann koennte das hier helfen:

Code: Alles auswählen

con = []
con.append(lambda x: x[1] - x[0] - 1)
con.append(lambda x: x[2] - x[0] - 1)
con.append(lambda x: x[3] - x[0] - 1)

bound_con = []
for i in range(1, 4):
    def get(x, i=i):
        return x[i]
    bound_con.append(lambda x: get(x) - x[0] - 1)

x = list(range(100))

for manual, generated in zip(con, bound_con):
    print(manual(x), generated(x))
Die generierten Funktionen behalten nach aussen hin die gleiche Signatur.

Re: Lambda Funktion

Verfasst: Freitag 10. Dezember 2021, 23:48
von th_goebi
Nachtrag: nach weiterer Suche im Netz und etwas Testen habe ich eine Lösung für mein Problem gefunden. Ich erstelle die Lambda-Funktionen zunächst als Strings und wandele sie dann mit "eval()" in die benötigten Funktionen um.
.....
str_lambda=[" "] * (n+1)
for i in range(1,n+1):
str_lambda = "lambda x : x[" + str(i) + "] - x[0] + 1"
funct_lambda = eval(str_lambda)
con = funct_lambda
.....
Damit funktioniert mein Code jetzt. Nochmals vielen Dank für eure Beiträge, die mir geholfen haben, diese Lösung zu finden.

Re: Lambda Funktion

Verfasst: Samstag 11. Dezember 2021, 00:31
von pillmuncher
@th_goebi: Das ist das brunzdümmste, was ich je gelesen habe. Gratulation!

Re: Lambda Funktion

Verfasst: Samstag 11. Dezember 2021, 01:28
von __blackjack__
@th_goebi: `eval()` ist so gut wie nie eine sinnvolle Lösung.

Re: Lambda Funktion

Verfasst: Samstag 11. Dezember 2021, 17:21
von __blackjack__
@th_goebi: Ich habe gerade durch Dich gelernt, dass man den Empfang privater Nachrichten deaktivieren kann. Das hast Du nämlich anscheinend, weshalb ich Dir nicht auf Deine private Nachricht antworten kann. 🤓 Jedenfalls nicht privat.

Deshalb öffentlich: `eval()` nicht verwenden weil das Böse™ ist („eval() is evil“). Das kann beliebige Python-Ausdrücke ausführen. Wenn dort Daten eingesetzt werden, die von aussen kommen, ist das im Zweifelsfall sogar gefährlich. Und letztlich kann da auch jeder Fehler auftreten, inklusive Syntaxfehler zur Laufzeit. Es ist also schwer da eine robuste und sinnvolle Fehlerbehandlung zu machen. Es ist auch nur sehr selten sinnvoll, denn wenn man zum generieren von Quelltext greift, muss das für ein Problem sein, dass man in der Sprache selbst nicht lösen kann. Das kann man aber. Du hast zwei Wege gezeigt bekommen die einfach sind, funktionieren, und genau für diesen Zweck gedacht sind, und ”innerhalb der Sprache” bleiben. Also ausnutzen, dass Defaultargumente zum Zeitpunkt der Funktionsdefinition ausgewertet werden, oder `functools.partial()`, das eingeführt wurde weil der Weg über Defaultargumente ein bisschen ”magisch” erscheinen mag, und man auch mal Fälle hat, wo man schon vorhandene, benannte Funktionen als Grundlage verwenden möchte.