funktionen definieren: def vs. lambda (newbee)

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
kommando_pimperlepim
User
Beiträge: 23
Registriert: Dienstag 3. April 2007, 05:32

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?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
kommando_pimperlepim
User
Beiträge: 23
Registriert: Dienstag 3. April 2007, 05:32

vielen dank für die schnelle antwort, Leonidas.
weiß jemand, ob es performanceunterschiede gibt?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

für normale Funktionen nutzen alle def.
lambda sieht man immer nur um 'einzeilige' Funktionen zu defenieren.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

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.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
thelittlebug
User
Beiträge: 188
Registriert: Donnerstag 20. Juli 2006, 20:46
Wohnort: Wien
Kontaktdaten:

hmm...

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

lgherby
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

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.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

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
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

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.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
kommando_pimperlepim
User
Beiträge: 23
Registriert: Dienstag 3. April 2007, 05:32

danke für deine hilfe, birkenfeld.
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

@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?
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

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() 
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

ach die möglichkeit hatte ich vergessen man kann ja funktionen in funktionen schreiben und diese funktionen haben zugriff auf die variablen.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Mr_Snede
User
Beiträge: 387
Registriert: Sonntag 8. Februar 2004, 16:02
Wohnort: D-Dorf, Bo

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
Zuletzt geändert von Mr_Snede am Dienstag 29. Mai 2007, 12:04, insgesamt 1-mal geändert.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

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.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
Mr_Snede
User
Beiträge: 387
Registriert: Sonntag 8. Februar 2004, 16:02
Wohnort: D-Dorf, Bo

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.
Antworten