Lambda-Funktion als Atribut einer Klasse

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
calo
User
Beiträge: 52
Registriert: Freitag 8. Dezember 2006, 21:35
Wohnort: Stuttgart

Hallo,

Ich möchte eine Lambda-Funktion mit verschiedenen Koeffizienten als Attribut einer Klasse abspeichern. Leider will das nicht so recht klappen. Kann mir da einer weiterhelfen?

Folgender Code:

Code: Alles auswählen

a = {23: (6622.3889855338457, 3.4964973502475862, 29.741146883501557),
     40: (5778.1500751826816, 2.7106131510817519, 32.674306382093654),
     60: (5298.5603201219001, 2.3384280000649538, 36.757223997745143)}

class Test(object):
    def __init__(self):
        self.fitfunc = {}

    def def_func(self):
        for T in a.keys():
            p = a[T]
            self.fitfunc[T] = lambda x: p[0]*x * ((1 - p[1]*x) / (1 + p[2]*x))
            print self.fitfunc[T](0.0005),
        print

b = Test()
b.def_func()
for T in (23, 40, 60):
    print b.fitfunc[T](0.0005),
Ausgabe ist dann:

Code: Alles auswählen

2.83878184138 2.59842710111 3.25697265039
3.25697265039 3.25697265039 3.25697265039
Die 1. Zeile gibt das korrekte Ergebnis wider. In der 2. Zeile würde ich das gleich erwarten. Es wird aber immer nur das Ergebnis für T=23 ausgegeben. Warum :? :?:

Calo
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo calo,

die Variable b ist im Namensraum der lambda-Funktion nicht definiert, also wird sie aus dem ihr übergeordneten Namensraum, der Funktion def_func genommen, dort ändert sich der Wert von p bei jedem Schleifendurchgang. Alle lambda-Funktionen besitzen also das gleiche p.
Als kleine Demonstration:

Code: Alles auswählen

>>> def get_func(a):
...   result = lambda: a
...   a*=2
...   return result
... 
>>> x=get_func(8)
>>> x()
16
Hier wird a innerhalb von get_func, aber nach dem Erzeugen der lambda-Funktion geändert.
BlackJack

@calo: Weil das `p` erst aufgelöst wird wenn die ``lambda``-Funktion ausgeführt wird, und zu *dem* Zeitpunkt ist `p` an den Wert gebunden, den es im letzten Schleifendurchlauf zugewiesen, bekommt wenn man es *nach* der Schleife aufruft.

Lösungsmöglichkeit: eine ``lambda``-Funktion die nicht nur `x` sondern auch `p` übergeben bekommt und das dann zum Beispiel als Default-Wert binden:

Code: Alles auswählen

    def def_func(self):
        for p, T in a.iteritems():
            self.fitfunc[T] = lambda x, p=p: p[0]*x * ((1 - p[1]*x) / (1 + p[2]*x))
            print self.fitfunc[T](0.0005),
        print
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

oder das Benutzen einer weiteren Funktion, die p an den aktuellen Wert bindet:

Code: Alles auswählen

def def_func(self):
        for T, p in a.iteritems():
            self.fitfunc[T] = (lambda p: lambda x: p[0]*x * ((1 - p[1]*x) / (1 + p[2]*x)))(p)
            print self.fitfunc[T](0.0005),
        print
calo
User
Beiträge: 52
Registriert: Freitag 8. Dezember 2006, 21:35
Wohnort: Stuttgart

Hi, super. Vielen Dank ... jetzt funktionierts :lol:
Antworten