Funktionsdefinition innerhalb einer Schleife

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
Knüppeltag
User
Beiträge: 3
Registriert: Sonntag 12. Juli 2009, 19:03

Hi,

habe bis jetzt immer nur in C programmiert und muss mich jetzt erstmal an python gewöhnen. Bis jetzt gefällt es mir aber super.
Allerdings hätte ich jetzt aber mal ein Frage zu Funktionsdefinitionen. In diesem Codebeispiel gibt es eine Funktionsdefinition in einer Schleife

Code: Alles auswählen

while True:
    # ... ein bischen code
    def draw_something(color, position):
        # ... inhalt der draw funktion

    draw_something(white, pos1)
    draw_something(green, pos2)
    draw_something(yellow, pos3)
    # ... weiterer code
Was passiert hier?
Wird jetzt in jedem Schleifendurchgang die Funktion 'draw_something' neu definiert werden und wenn ja, wäre das nicht ziemlich langsam?

Danke schon mal
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Knüppeltag hat geschrieben: Was passiert hier?
Wird jetzt in jedem Schleifendurchgang die Funktion 'draw_something' neu definiert
Ja, so ist es. Allem Anschein nach ist das von jemandem ziemlich schlecht programmiert worden. Die Funktionsdefinition gehört nicht in die Schleife.
Knüppeltag
User
Beiträge: 3
Registriert: Sonntag 12. Juli 2009, 19:03

Das ist aus dem Buch 'Beginning Game Development with Python and Pygame'. Dort wird das laufend so gemacht. Manchmal sind es sogar mehr als 2 Funktionsdefinitionen in einer Schleife.

Das spricht dann ja nicht gerade für den Autor.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Naja, ohne Profiling müsste man es nicht unbedingt verurteilen. Vielleicht ist es ja eine Closure oder der Programmierer stammt aus einer Sprache in der anonyme Funktionen populärer sind als in Python.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

@Knüppeltag: Man kann zu dem Buch Quelltexte herunterladen: http://www.apress.com/book/downloadfile/3765

Da wird das soweit ich das sehen kann nur *einmal* in 12 Kapiteln gemacht. In Kapitel 8 bei `rotation3d.py`.

Kann es sein, dass im Buchtext der Quelltext unterbrochen von Absätzen nicht linear gezeigt wird!?

Ansonsten sehen die Quelltexte, zumindest so vom kurz drüberschauen, auch nicht besonders "schlimm" aus.
Knüppeltag
User
Beiträge: 3
Registriert: Sonntag 12. Juli 2009, 19:03

Hehe, das mt dem "laufend" war wohl etwas übertrieben :D. Es kommt tatsächlich nur in rotation3d.py vor.
Ansonsten sehen die Quelltexte, zumindest so vom kurz drüberschauen, auch nicht besonders "schlimm" aus.
Ja, die Quelltexte sehen nicht schlimm aus. Eigentlich wollte ich nur wissen, ob das ein anerkannter Python coding style oder so ähnlich ist. Also, dass man Funktionen einfach so in einer Schleife definiert.
Aber da das anscheinend wirklich die Performance verschlechtert, sollte man das wohl lieber nicht auf diese Weise machen.
Für kleine Testprogramme wie im Buch, ist es aber dann wohl legitim. Kann man das so sagen?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Knüppeltag hat geschrieben:Für kleine Testprogramme wie im Buch, ist es aber dann wohl legitim. Kann man das so sagen?
Legitim ist alles was der Interpreter frisst und die Entwickler sich und anderen zumuten - nicht zuletzt den Anwendern im Hinblick auf Performance.

Obiges gilt fuer Produktionscode, was du dagegen in deinem Sandkasten aka
interaktive Interpretersession machst, ist ganz egal ;)

Wenn dich das Thema Coding Style interessiert, solltest du [wiki]PEP 8 (Übersetzung)[/wiki] oder das Original anschauen.
Dort werden solche Details zwar nicht angesprochen, dafuer aber der Rest. Ob du den Stil des Buches anwendest bleibt dir und deinem (gesunden) Menschenverstand ueberlassen (PEP 8 ist aber drigend empfohlen :twisted:)

Wenn du dazu eine Hilfe willst:

Code: Alles auswählen

import this
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Knüppeltag hat geschrieben:Aber da das anscheinend wirklich die Performance verschlechtert, sollte man das wohl lieber nicht auf diese Weise machen.
Ich würde das nicht überbewerten, Python ist ja sowieso schon vergleichsweise langsam. Wie heißt es so schön: „Premature optimization is the root of all evil.“
BlackJack

@Knüppeltag: Also ich würde das als kleineren Schönheitsfehler ansehen. Das ist so ähnlich wie das Ausrechnen eines Wertes in einer Schleife, wo sich der Wert aber garantiert nie ändert. Also etwas das man vor die Schleife ziehen sollte.

"Erschwerend" kommt hier dazu, dass so eine Funtkionsdefinition eher die Frage aufwirft *warum* das in der Schleife gemacht wird, und der Leser ein wenig Zeit darauf ver(sch)wenden muss, ob das einen Sinn hat, oder nicht. Wenn ich so etwas in einer Schleife sehe, denke ich zuerst an ein Closure.
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Darii hat geschrieben:Ich würde das nicht überbewerten, Python ist ja sowieso schon vergleichsweise langsam. Wie heißt es so schön: „Premature optimization is the root of all evil.“
Funktionsdefinition in einer Schleife ist einfach suboptimal. Da gibt es nichts zu beschwichtigen.
BlackJack

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

So furchtbar, wie manche das hier darstellen, sind Funktionsdefinitionen in einer Schleife nicht. Da die Funktion nur einmal kompiliert wird, fällt pro Durchlauf nur ein Laden des konstanten Codeobjekts und erstellen eines Funktionsobjekts daraus an.

Dass das bei komplizierten Funktionen bald vernachlässigbar wird, sieht man z.B. hieran:

Code: Alles auswählen

import math, time

def a():
    for i in xrange(1, 1000000):
        def foo(x):
            math.log(x) + 1 - math.exp(1 - x**2)
        foo(i)

def b():
    def foo(x):
        math.log(x) + 1 - math.exp(1 - x**2)
    for i in xrange(1, 1000000):
        foo(i)

def c():
    for x in xrange(1, 1000000):
        math.log(x) + 1 - math.exp(1 - x**2)


x1 = time.time()
a()
x2 = time.time()
b()
x3 = time.time()
c()
x4 = time.time()

print 'innerhalb:', x2-x1
print 'ausserhalb:', x3-x2
print 'ohne fkt:', x4-x3
Bei mir gibt das aus:

Code: Alles auswählen

innerhalb: 6.42580318451
ausserhalb: 6.02840685844
ohne fkt: 5.32613611221
Die zusätzliche Funktionsdefinition macht also unter 10% zusätzlicher Laufzeit aus, und das, obwohl in der Funktion "nur" ein paar einfache mathematische Operationen ausgeführt werden.

Der Funktionsaufruf "kostet" sogar mehr als die Funktionsdefinition, wie man am letzten Beispiel sieht!
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Kann ich bestätigen. Hab auch ein bißchen rumexperimentiert. Performanceeinbußen sind relativ gering. In meinem Test etwa 4%. Sympatisch ist mir das trotzdem nicht.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Klar. In den meisten Fällen ist es denke ich einfach ein Versehen.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

In dem speziellen Fall wäre die Alternative ein Funktionsaufruf mit 7 Parametern von denen sich die 4 zusätzlichen nicht unterscheiden. Wenn man sich so viel Sorgen um die Geschwindigkeit macht, hätte man imo nicht Python nehmen sollen (ich will damit nicht sagen, dass man deswegen ohne Sinn und Verstand vorgehen sollte).
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Darii hat geschrieben:In dem speziellen Fall wäre die Alternative ein Funktionsaufruf mit 7 Parametern von denen sich die 4 zusätzlichen nicht unterscheiden.
Dazu braucht man die Funktion aber nicht in der Schleife definieren.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

birkenfeld hat geschrieben:
Darii hat geschrieben:In dem speziellen Fall wäre die Alternative ein Funktionsaufruf mit 7 Parametern von denen sich die 4 zusätzlichen nicht unterscheiden.
Dazu braucht man die Funktion aber nicht in der Schleife definieren.
? Sage ich doch. Wenn man die Funktion nicht in der Schleife definieren würde, bräuchte man alternativ 7 Parametern von denen sich die 4 zusätzlichen wiederholen.

Code: Alles auswählen

        draw_axis(red, x_axis, x_surface,   screen, viewing_distance, rotation_matrix, camera_position)
        draw_axis(green, y_axis, y_surface, screen, viewing_distance, rotation_matrix, camera_position)
        draw_axis(blue, z_axis, z_surface,  screen, viewing_distance, rotation_matrix, camera_position)
Edit: ok screen könnte man sich noch schenken, das wars aber schon...
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Nein, das bräuchte man eben nicht. Diese Namen kannst du in der Funktion verwenden, und sie werden automatisch im umgebenden Namensraum gefunden.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Closures ftw.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

birkenfeld hat geschrieben:Nein, das bräuchte man eben nicht. Diese Namen kannst du in der Funktion verwenden, und sie werden automatisch im umgebenden Namensraum gefunden.
Ach mist stimmt, ich hatte total übersehen dass Schleifen ja gar keinen neuen Namenraum haben.
Antworten