Funktionen in Schleife generieren

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
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Hallo,

ich muss zur Laufzeit ein paar Funktionen generieren, die nachher an andere Stelle wichtig sind. Die Funktionen werden in einer Schleife definiert und an eine List angehängt.

Mein Problem besteht jetzt darin, dass immer nur die Werte aus dem letzten Schleifendurchgang in alle generierten Funktionen eingesetzt werden.

Hier ein vereinfachtes Beispiel:

Code: Alles auswählen

for i in range(3):
  fn.append(lambda x: i*x)

for func in fn:
  for j in range(5):
    print func(j),
  print

"""
Ausgabe:
0 2 4 6 8
0 2 4 6 8
0 2 4 6 8
"""

fn = list()

for i in range(3):
  def curFunc(x):
    return x*i
  fn.append(curFunc)

for func in fn:
  for j in range(5):
    print func(j),
  print

"""
Ausgabe:
0 2 4 6 8
0 2 4 6 8
0 2 4 6 8
"""
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

IoI hat geschrieben: Mein Problem besteht jetzt darin, dass immer nur die Werte aus dem letzten Schleifendurchgang in alle generierten Funktionen eingesetzt werden.
So ist eben der Scope einer lambda-Funktion definiert. Leider etwas magic...
Wenn du uns dein eigentliches Vorhaben erläuterst, können wir dir bestimmt eine gute Alternative vorschlagen.
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Ich habe in der Schleife verschiedene sympy Funktionen z.B. func = -5*y+3*x*y+x**2 und will jetzt eine Funktion zurück geben in der nachher x und y eingesetzt werden können also lambda wertx,werty: float(func.subs({'x':wertx, 'y':werty}))
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wenn ich das richtig verstehe mach 's doch so:

Code: Alles auswählen

def eval_func(func, **kwargs)
    return float(func.subs(kwargs))
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Hyperion hat geschrieben:Wenn ich das richtig verstehe mach 's doch so:

Code: Alles auswählen

def eval_func(func, **kwargs)
    return float(func.subs(kwargs))
func ändert sich aber auch mit jeder Schleife.
BlackJack

@IoI: Das `i` wird zur Zeit des *Aufrufs* zu einem Wert aufgelöst und nicht zu dem Zeitpunkt an dem die Funktion, ob nun mit ``lambda`` oder mit ``def``, definiert wird.

Lösung: Das in der Funktion lokal binden, zum Beispiel über ein Default-Argument. Das wird nämlich bei der Definition der Funktion ausgewertet:

Code: Alles auswählen

lambda x, i=i: i*x
Alternativ mit `functools.partial()`:

Code: Alles auswählen

partial((lambda i, x: i*x), i)
Zuletzt geändert von BlackJack am Montag 10. Mai 2010, 10:46, insgesamt 1-mal geändert.
Grund: Klammern um den ``lambda``-Ausdruck bei `partial()` gesetzt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

IoI hat geschrieben: func ändert sich aber auch mit jeder Schleife.
Wo kommen denn die Änderungen her? Ist das nur dieses "i"?

Letztlich könntest Du das "i" doch hier auch noch übergeben... oder eben mit partial arbeiten und diese Objekte dann in eine Liste packen, wie BlackJack es vorschlug.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Yeah, genau was ich gesucht habe, danke BlackJack.
Antworten