Seite 1 von 1

funktionen definieren: def vs. lambda (newbee)

Verfasst: Montag 28. Mai 2007, 11:11
von kommando_pimperlepim
ich bin mir in letzter zeit immer wieder unsicher, ob ich richtig handle, wenn ich zwei funktionen definiere, wobei eine die andere verwendet. in welchem fall ist es richtig, davon auszugehen, dass die eine funktion die andere "kennt"? zunächst funktionieren alle der folgenden 4 möglichkeiten:

Code: Alles auswählen

# beispiel 1 
def f1(x):
    return x+1
def f2(x):
    return f1(x)+1
print f2(1)

# beispiel 2
f1 = lambda x: x+1
def f2(x):
    return f1(x)+1
print f2(1)

# beispiel 3
def f1(x):
    return x+1
f2= lambda x: f1(x)+1
print f2(1)

# beispiel 4
f1 = lambda x: x+1
f2 = lambda x: f1(x)+1
print f2(1)
könnte es passieren, dass bei einem import von f2 aus beispiel 1 oder 2 durch eine externe py-datei probleme auftreten?
ist eine der 4 möglichkeiten aus anderen gründen den anderen vorzuziehen?
oder sind sie alle komplett gleichwertig?

Verfasst: Montag 28. Mai 2007, 11:14
von Leonidas
Ob du eine Funktion nun per ``lambda`` oder ``def`` definierst ist, wenn die Funktion schon existiert völlig egal. Sie verhalten sich beide wie ``Callables``. Der einzige Unterschied in ``lambda`` ist, dass man keine Statements nutzen kann (also keine Schlüsselwörter), was lambda zu einer recht beschränkten Sache macht.

?

Verfasst: Montag 28. Mai 2007, 12:35
von kommando_pimperlepim
vielen dank für die schnelle antwort, Leonidas.
weiß jemand, ob es performanceunterschiede gibt?

Verfasst: Montag 28. Mai 2007, 16:55
von Leonidas
Testen? Mit ``timeit`` hast du schon das passende Modul zur Hand, im Wiki wird auch erklärt wie man es nutzt.

Aber ich persönlich finde es sinnlos, sowas auf Performance-Unterschiede zu testen: "Premature optimalization is the root of all evil" (das sollte in den Zen aufgenommen werden). Nimm das was leserlicher ist. Oder das wann an einer gegebenen Stelle sinnvoll ist.

Verfasst: Montag 28. Mai 2007, 17:20
von Sr4l
für normale Funktionen nutzen alle def.
lambda sieht man immer nur um 'einzeilige' Funktionen zu defenieren.

Re: ?

Verfasst: Montag 28. Mai 2007, 19:23
von birkenfeld
kommando_pimperlepim hat geschrieben:vielen dank für die schnelle antwort, Leonidas.
weiß jemand, ob es performanceunterschiede gibt?
Ja. Es gibt absolut keine, weder bei der Definition noch der Ausführung.

Verfasst: Montag 28. Mai 2007, 20:55
von thelittlebug
hmm...

ich hab lambda noch nicht "verstanden" :) wofür kann man das wirklich mal brauchen?

lgherby

Verfasst: Montag 28. Mai 2007, 21:11
von birkenfeld
Zum Beispiel für

Code: Alles auswählen

l = [("hello", 0), ("World", 1), ("world", 2), ("HELLo", -10)]
l.sort(key=lambda x: x[0].lower())
Das gleiche könnte man natürlich auch mit einer Funktion mit Namen machen:

Code: Alles auswählen

l = [("hello", 0), ("World", 1), ("world", 2), ("HELLo", -10)]
def keyfunc(x):
    return x[0].lower()
l.sort(key=keyfunc)
Für solche Oneliner-Funktionen ist lambda aber wirklich schöner.

Verfasst: Montag 28. Mai 2007, 22:01
von Sr4l
Es gibt auch einen Einsatzfall wo man es braucht.
Um beim drücken von GUI Buttons Variablen zuübergeben siehe:
http://www.python-forum.de/topic-8813.html

Verfasst: Montag 28. Mai 2007, 22:05
von birkenfeld
Brauchen tut man es nie. Man kann *immer* eine entsprechende Funktion mit `def` erstellen.

Die Frage ist nur, was schöner und besser lesbar ist.

...

Verfasst: Dienstag 29. Mai 2007, 06:42
von kommando_pimperlepim
danke für deine hilfe, birkenfeld.

Verfasst: Dienstag 29. Mai 2007, 08:20
von Sr4l
@birkenfeld wenn du bei GUI Variablen übergabe auf lambda verzichtest, hilft da auch kein def. Da muss man schon auf globals zurückgreifen
Oder wie wäre deine Lösung?

Verfasst: Dienstag 29. Mai 2007, 08:26
von birkenfeld
Sehen wir uns doch das Beispiel aus dem verlinkten Post an:

Code: Alles auswählen

class ClassTKWINDOW:
    def __init__(self,master):
        self.but = Button(master, text="test", command=lambda: textmalen('hallo welt'))
        self.but.pack() 
Das geht auch mit einer Funktion mit Namen:

Code: Alles auswählen

class ClassTKWINDOW:
    def __init__(self,master):
        def callback():
            textmalen('hallo welt')
        self.but = Button(master, text="test", command=callback)
        self.but.pack() 

Verfasst: Dienstag 29. Mai 2007, 11:32
von Sr4l
ach die möglichkeit hatte ich vergessen man kann ja funktionen in funktionen schreiben und diese funktionen haben zugriff auf die variablen.

Verfasst: Dienstag 29. Mai 2007, 11:35
von Leonidas
Sr4l hat geschrieben:ach die möglichkeit hatte ich vergessen man kann ja funktionen in funktionen schreiben und diese funktionen haben zugriff auf die variablen.
Davon abgesehen sieht man ``lambda``s hauptsächlich in Tkinter. In anderen Toolkits kann man Callback-Funktionen Parameter mitgeben, bzw. die wichtigsten Parameter werden implizit mitgegeben.

Verfasst: Dienstag 29. Mai 2007, 11:59
von Mr_Snede
Genau, bei Tkinter Buttons ist Lambda sehr praktisch.
Speziell, wenn mann einen Schwung an Knöpfen generieren möchte.
Soll an diese Knöpfe dann eine Funktion gebunden werden, deren Verhalten sich auf Grund von Übergabeparametern unterscheiden soll wüsste ich im Moment keinen andere Möglichkeit.

Im unteren Beispiel habe ich einen Auszug aus einem aktuellen Projekt.
Mit dieser Funktion kann im "try" Block eine Funktion an die Knöpfe gebunden werden, die sich durch Übergabeparameter von Knopf zu Knopf unterscheidet.
(Hier: einem markiertem Text wird am Anfang und am Ende mit Textzeichen erweitert, jeder Knopf fügt unterschiedliche Textzeichen hinzu.)

Ich wüste nicht, wie ich das ohne lambda hinbekommen würde.

Code: Alles auswählen

    def label_button_row(self, parent_widget=None,
                            btnlst=None, start_count=0):
        """Build a 2 column table with a label beside each button in a row.
        Bind a keyboard sequence to the button command.
        Display this keyboard sequence on the label.

        todo:
            - think about a parameter for the widget to bind the Hotkeys
            - rename to: labled_button_row, draw_labled_button_row

        Parameter:
        --> parent_widget:
                Parent widget to place the table

        --> btnlst:
                Type: List of dicts representing a button
                Example:
                    {'text':'**bold**',     # displayed on the Button (string)
                    'cmd':self.on_tag_insert,   # command
                    'open_tag':'**',        # chars representing the beginning
                                            # of a tag for inserting (string)
                    'close_tag':'**',       # chars representing the end
                                            # of a tag for inserting (string)
                    'keytxt':'CTRL+b',      # displayed on the Label (string)
                    'hotkey':'<Control-b>'} # keyboard sequence (string)
                Note:
                    The existence of 'open_tag' and 'close_tag' in btnlst
                    decides which command is bound to the Button.
                    If they aren't there 'cmd' must be a function without
                    parameters!!!
                    otherwise 'cmd' needs following parameters:
                        otag = btn['open_tag']
                        ctag = btn['close_tag']
                        event = None  # Placeholder for a keysequence

        --> start_count:
                Type: int

                Description:
                    The table is relized with tkinter grid layout manager.
                    start_count is used if there is already a grid
                    (with a Label beside a button).
                    start_count can add the automatic genrated
                    buttons under the existing.
                    In Wombat_Editor it is used to put a label_button_row
                    under a Tkinter menubutton(file choose, headlines).
        """
        i = start_count
        for btn in btnlst:
            try:
                otag = btn['open_tag']
                ctag = btn['close_tag']
                event = None
                doit = lambda e=event, o=otag, c=ctag:self.on_tag_insert(e,o,c)
                tk.Button(parent_widget, text=btn['text'], command=doit,
                        relief=tk.RIDGE
                        ).grid(column=0, row=i, sticky=tk.W+tk.E)
                self.text.bind(btn['hotkey'],doit)
            except KeyError:
                # generate buttons with an unique command  for every button 
                tk.Button(parent_widget, text=btn['text'], command=btn['cmd'],
                        relief=tk.RIDGE
                        ).grid(column=0, row=i, sticky=tk.W+tk.E)
            tk.Label(parent_widget, text=btn['keytxt'], relief=tk.FLAT
                ).grid(column=1, row=i, sticky=tk.W)
            i +=1

Verfasst: Dienstag 29. Mai 2007, 12:03
von birkenfeld
Wie oft soll ich denn noch erklären, dass man *jede* Benutzung von `lambda` mit einer `def`-Konstruktion ersetzen kann.

Gerade in deinem Beispiel weist du ja die Lambdafunktion gerade einem Namen zu.

Verfasst: Dienstag 29. Mai 2007, 12:09
von Mr_Snede
Och menno, warum ist mir das nicht selbst aufgefallen.
Peinlich, peinlich
- aber danke für den Schlag auf den Hinterkopf - hatte ich wohl nötig.