Seite 1 von 1

Klassenkonstruktor verändert sich nach Funktionsaufruf

Verfasst: Freitag 11. Januar 2008, 15:14
von Nikolas
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?

Verfasst: Freitag 11. Januar 2008, 15:26
von Leonidas
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.

Verfasst: Freitag 11. Januar 2008, 15:39
von Nikolas
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.

Verfasst: Freitag 11. Januar 2008, 15:46
von Leonidas
Achja, und 'childs' gibts nicht - der Plural von 'child' ist 'children' :)

Verfasst: Freitag 11. Januar 2008, 15:57
von 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.

Verfasst: Freitag 11. Januar 2008, 16:10
von Nikolas
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.

Verfasst: Freitag 11. Januar 2008, 16:28
von 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. :-)