PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Python: Liste als Member statisch?


Marscel
2007-11-27, 17:29:41
class blub:
list = []

def __init__(self):
print len(self.list)

def incr(self):
if len(self.list) < 10:
bla = blub()
self.list.append(bla)
bla.incr()

a = blub()
a.incr()

Warum zur Hölle erhalte ich diese Ausgabe?

0
0
1
2
3
4
5
6
7
8
9

Eigentlich hatte ich hier eine Warnung wegen Rekursion erwartet (das ganze ist ein Testscript, Sinnfreiheit ist deswegen präsent), aber blub::list ist offenbar statisch. Wieso? Wenn ich statt einer Variablen vom Typ list einfach einen Integer nehme, ist alles, wie es soll (d.h., Inkrementieren wird nur auf das jew Objekt angwendet).

Hintergrund ist eigentlich, ich will eine Baumstruktur, die nur eine Klasse hat, die wiederum soll selbstständig rekursiv aufgebaut werden, also jeweils in einer Liste (da später mehrere) alle Kinderknoten speichern. Das funktioniert aber nicht, wenn sie offenbar alle Objekte den Member 'list' teilen. Ich gehe mal davon aus, das 'self' für die bound-Funktion 'incr' ist irgendwie der springende Punkt...

Xmas
2007-11-27, 20:19:27
Eigentlich hatte ich hier eine Warnung wegen Rekursion erwartet
Warnung wegen Rekursion? Warum?

class blub:
list = []
list ist nicht statisch. Das tückische ist dass hier der Ausdruck "[]" nur ein einziges Mal ausgewertet wird, danach erhält jede Instanz eine Kopie derselben Referenz. Sprich die list-Membervariable aller Instanzen von blub zeigt auf dieselbe Liste.

Du solltest dir lieber angewöhnen Membervariablen im Konstruktor zu initialisieren.

Ein ähnliches Problem gibt es übrigens bei Default-Parametern:
def egg(spam = []):
spam.append(1)
print spam

egg()
egg()

Mad-Marty
2007-11-27, 21:46:48
class blub:
list = []

def __init__(self):
print len(self.list)

def incr(self):
if len(self.list) < 10:
bla = blub()
self.list.append(bla)
bla.incr()

a = blub()
a.incr()

Warum zur Hölle erhalte ich diese Ausgabe?



Eigentlich hatte ich hier eine Warnung wegen Rekursion erwartet (das ganze ist ein Testscript, Sinnfreiheit ist deswegen präsent), aber blub::list ist offenbar statisch. Wieso? Wenn ich statt einer Variablen vom Typ list einfach einen Integer nehme, ist alles, wie es soll (d.h., Inkrementieren wird nur auf das jew Objekt angwendet).

Hintergrund ist eigentlich, ich will eine Baumstruktur, die nur eine Klasse hat, die wiederum soll selbstständig rekursiv aufgebaut werden, also jeweils in einer Liste (da später mehrere) alle Kinderknoten speichern. Das funktioniert aber nicht, wenn sie offenbar alle Objekte den Member 'list' teilen. Ich gehe mal davon aus, das 'self' für die bound-Funktion 'incr' ist irgendwie der springende Punkt...


Klassenspezifische Attribute die von allen Instanzen geteilt werden sind für
spezifische Sachen wie z.b. Singleton gedacht.

Das problem ist das Python schonmal nicht statisch ist und listen eben veränderbar.
Wie Xmas schon sagte, alle deine Instanzen teilen sich dieselbe liste.


Am besten du änderst das auf:
class blub:
def __init__(self):
self.list = []
print len(self.list)

def incr(self):
self.list.append(1)

def get_list(self):
return self.list

a = blub()
for i in xrange(10):
a.incr()
a.get_list()

Marscel
2007-11-27, 22:19:26
Warnung wegen Rekursion? Warum?

Weil ich bis zu deiner Erklärung eigentlich erwartete, dass die len-Funktion nie mehr als 1 zurückgibt, also unendlich viele Instanzen nach unten erstellt werden.

class blub:
list = []
list ist nicht statisch. Das tückische ist dass hier der Ausdruck "[]" nur ein einziges Mal ausgewertet wird, danach erhält jede Instanz eine Kopie derselben Referenz. Sprich die list-Membervariable aller Instanzen von blub zeigt auf dieselbe Liste.

Du solltest dir lieber angewöhnen Membervariablen im Konstruktor zu initialisieren.

Ok, leuchtet ein. Werd ich also in Zukunft alles im Pointerstil unter Python bauen.


Am besten du änderst das auf:
class blub:
def __init__(self):
self.list = []
print len(self.list)

def incr(self):
self.list.append(1)

def get_list(self):
return self.list

a = blub()
for i in xrange(10):
a.incr()
a.get_list()

Wäre es so einfach, ja. Aber ich will das Dateisystem darstellen, da soll jede Instanz eine Datei oder einen Ordner darstellen, und Ordner müssen selber dafür sorgen, dass ihre Inhalte wiederum aufgekettet werden.

Aber danke für den Hinweis ihr beiden, nun hab ich, was ich wollte!

Mad-Marty
2007-11-27, 23:45:52
Für dateisystem repräsentation würd ich dir das Composite-Pattern empfehlen. Auserdem erstelle bitte nur noch Klassen die von Object ableiten,
old style classes sind eigentlich schon deprecated.

Marscel
2007-11-28, 00:05:58
Für dateisystem repräsentation würd ich dir das Composite-Pattern empfehlen.

Da müsste ich mich reinarbeiten, was das im Detail ist. Ich hab nun meine Baumstruktur, die von einer anderen Funktion durchgeschaut wird, um diese zu visualisieren, damit bin ich jetzt eigentlich ganz glücklich.

Auserdem erstelle bitte nur noch Klassen die von Object ableiten,
old style classes sind eigentlich schon deprecated.

Wozu das? Ich bin erst seit kurzem in Python drinnen.

Mad-Marty
2007-12-01, 12:20:40
Wozu das? Ich bin erst seit kurzem in Python drinnen.


class MyClass:
...

vs

class MyClass(object):
...

Das 1. wird in absehbarer zukunft nicht mehr unterstützt, auserdem gibt es damit ein paar probleme bezüglich MRO bzw Multiple Inheritance, deswegen gleich auf new-style klassen setzen.

mehr infos:
http://www.geocities.com/foetsch/python/new_style_classes.htm
http://www.python.org/doc/newstyle.html