Klassenkonstruktor verändert sich nach Funktionsaufruf

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
Nikolas
User
Beiträge: 102
Registriert: Dienstag 25. Dezember 2007, 22:53
Wohnort: Freiburg im Breisgau

Ich baue mir gerade eine Baumklasse, für die ich ein paar Funktionen implementieren will. Der Konstruktor hat per Default eine leere Liste, die dafür gedacht ist, Kinder mit anzugeben.

Wenn ich jetzt ein Instanz konstuiere und ein append auf diese Liste aufführe (s.u. add) bekommt jede neue Instanz statt dieser leeren Liste als default, den Wert der in als node in die add-Funktion geschrieben wurde, als default.

Code: Alles auswählen

class Node():
    def __init__(self,value=None, childs = []):

        self.arg={"value":value,
                  "childs":childs}
        
        self._update()

    def _update(self):
        cnt = self.childCnt()
        # (...) anzahl Kinder usw. wird neu berechnet

    def add(self,node):
        self.arg["childs"].append(node)
 
Könnte mir da jemand auf die sprünge helfen?
Erwarte das Beste und sei auf das Schlimmste vorbereitet.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

In Funktionensignaturen nie Mutable Objekte verwenden, das funktioniert in der Regel ganz seltsam. Setze es besser auf ``None``, und prüfe das innerhalb der Funktion, wo du ganz einfach testen kannst ob es ``None`` ist oder nicht und dann eine Liste erstellen kannst.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Nikolas
User
Beiträge: 102
Registriert: Dienstag 25. Dezember 2007, 22:53
Wohnort: Freiburg im Breisgau

Gute Idee, jetzt habe ich das Problem nicht mehr.
Nur warum ist das passiert? Da ich ein self. vor dem args hatte, habe ich ja explizit die Instanz und nicht die Klasse angesprochen.
Erwarte das Beste und sei auf das Schlimmste vorbereitet.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Achja, und 'childs' gibts nicht - der Plural von 'child' ist 'children' :)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

@Nikolas: Das ist passiert, weil Default-Argumente nur einmal ausgewertet werden, nämlich dann wenn das ``def`` ausgeführt wird. Und eben nicht bei jedem Aufruf der Funktion.
Nikolas
User
Beiträge: 102
Registriert: Dienstag 25. Dezember 2007, 22:53
Wohnort: Freiburg im Breisgau

Achja, und 'childs' gibts nicht - der Plural von 'child' ist 'children'
Ich weiss. Nur ist es verständlich und das s kann ich schnell mit dem Mittelfinger tippen und für ren müsste ich den Zeigefinger umsetzen und auch noch die andere Hand benutzen :lol:

--
Aber zu welchem Zeitpunkt hat sich denn dieser Wert geändert? Wenn ich die richtig verstehe, wird das def für __init__ einmal ausgeführt und zwar dann, wenn jemand das Modul läd und eine Instanz haben will. Zu diesem zeitpunkt stimmt alles, nur später nicht mehr, was eigentlich dagegen sprechen würde, dass dieses def nur einmal ausgeführt wird.
Erwarte das Beste und sei auf das Schlimmste vorbereitet.
BlackJack

Wenn Du zwei `Node`-Objekte ohne Angabe von `childs` erstellst, dann haben beide die *gleiche* leere Liste. Wenn Du an diese *eine* Liste dann etwas anhängst, ist das natürlich in beiden Knoten sichtbar. Der Beweis das es die selbe Liste ist:

Code: Alles auswählen

a = Node()
b = Node()
print id(a.args['childs']), id(b.args['childs'])
print a.args['childs'] is b.args['childs']
Was das umständliche tippen angeht: Quelltext wird öfter gelesen als geschrieben, darum sollte man nicht am falschen Ende bei der Bequemlichkeit sparen und für die meisten Editoren braucht man nur drei bis vier Buchstaben tippen und man sucht sich dann den richtigen Kandidaten aus der Autovervollständigung aus. :-)
Antworten