Default Parameter list

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
Gregorrr
User
Beiträge: 22
Registriert: Montag 25. Juli 2011, 21:55

Huch, was ist da los:
Ich habe einen list Default-Parameter, der mutable ist.

Code: Alles auswählen

def append_num(x, items=[]):
    items.append(x)
    return items

append_num(1) # [1]
append_num(2) # [1, 2]
append_num(3) # [1, 2, 3]
Warum wird nicht jedes mal eine neue Liste mit leerem Inhalt erstellt? Ich mein, eigentlich müsste doch der GC hingehen und die lokale Variable items, die ja keinen Scope mehr hat, beseitigen.

Danke schonmal!
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

items wird beim ersten Aufruf fest gebunden. Um hier das von dir gewünschte Verhalten zu bekommen bietet sich folgender Code an.

Code: Alles auswählen

def append_num(x, items=None):
    if not items:
        items = []
    items.append(x)
    return items
lunar

@Gregorrr: "items" ist nicht lokal. Der Ausdruck für den Standardwert wird bei der Erzeugung der Funktion (und nicht bei deren Aufruf) ausgewertet. Das Ergebnis dieses Ausdrucks wird dann an das Funktionsobjekt gebunden, und somit global. Für eine vollständige Erklärung siehe Default Parameter Values in Python von Fredrik Lundh.

Die übliche Vorgehensweise zur Vermeidung dieses Effekts hat /me Dir bereits gezeigt, anzumerken ist noch, dass dieser Effekt jeden veränderbaren Typen betrifft, also nicht nur Listen, sondern auch Wörterbücher, Mengen, und Klassen-Exemplare. Daher ist das von /me gezeigte Idiom der übliche Weg, um Standardwerte jeglicher Art für Argumente vorzugeben. Nur bei wenigen Typen (Zeichenketten, Zahlen und Tupel sowie davon abgeleitete Klassen wie "collections.namedtuple()") gibt man den Standardwert direkt an.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Stat `not items` sollte besser `items is not None` verwendet werden. Vielleicht möchte man tatsächlich mal eine leere Liste übergeben, welche in-place verändert wird.
Das Leben ist wie ein Tennisball.
Gregorrr
User
Beiträge: 22
Registriert: Montag 25. Juli 2011, 21:55

Wow, vielen vielen Dank @lunar. Genau diese Erklärung habe ich gesucht. :)
Und danke /me und Eydu für die Idiome.

Die funktionalen Bestandteile von Python sind eine spannende Sache, vor allem wenn man aus der Java Welt kommt. :)
Antworten