Seite 1 von 1

Klassenvariablen

Verfasst: Freitag 4. Juli 2008, 23:43
von Pekh
Kann mir das jemand mal bitte erklären? Wenn ich statt des Dicts z.B. einen Integer hinterlege, funktioniert es. :?

Code: Alles auswählen

In [13]: class T(object):
   ....:     objects = {}
   ....:     
   ....:     def t(self):
   ....:         return T.objects
   ....:     
   ....:     

In [14]: t = T()

In [15]: t.objects={"A":3}

In [16]: t.t()
Out[16]: {}

In [17]: t.objects
Out[17]: {'A': 3}

Verfasst: Freitag 4. Juli 2008, 23:48
von Karl
hast du das ``self`` vielleicht vergessen? ;)

Verfasst: Freitag 4. Juli 2008, 23:50
von Pekh
Nein. Ist ja schließlich eine Klassenvariable und keine Instanzvariable. Aber trotzdem danke.

Verfasst: Samstag 5. Juli 2008, 00:26
von cofi
Man kann Klassenvariablen nicht von aussen verändern, so weit ich weiss.

Code: Alles auswählen

class a(object):
    x = {}
    def set(self):
        a.x["key"] = "value"
    def get(self):
        return a.x
Klappt beispielsweise.

Verfasst: Samstag 5. Juli 2008, 00:45
von Karl
Oh sorry stimmt schon, dass da kein self fehlt. Ich hab mich wohl verguckt.

Dass Klassenvariablen nicht von außen veränderbar sind unterstützt folgendes:

Code: Alles auswählen

>>> class T(object):
	objects = {}
	def print_self(self):
		print self.objects
	def print_objects(self):
		print T.objects

		
>>> t = T()
>>> t.print_self()
{}
>>> t.print_objects()
{}
>>> t.objects = "lol"
>>> t.print_self()
lol
>>> t.print_objects()
{}
Anscheinend wird dann durch t.objects = wert ein neues Attribut angelegt, was deine Frage wohl klären dürfte.

Verfasst: Samstag 5. Juli 2008, 00:49
von Pekh
Ja, das scheint tatsächlich die Lösung zu sein. Vielen Dank euch beiden. Habe das Problem jetzt dadurch umgangen, daß ich nicht t.objects sondern gleich T.objects von außen manipuliere.

Verfasst: Samstag 5. Juli 2008, 00:52
von Karl
Pekh hat geschrieben:Ja, das scheint tatsächlich die Lösung zu sein. Vielen Dank euch beiden. Habe das Problem jetzt dadurch umgangen, daß ich nicht t.objects sondern gleich T.objects von außen manipuliere.
Du kannst ja auch wie confi das vorgeschlagen hat, einfach eine Methode zwischenschalten.

Verfasst: Samstag 5. Juli 2008, 00:57
von Pekh
Könnte ich, aber an der Stelle hat das keinen praktischen Mehrwert. Vielleicht ändere ich das irgendwann mal im Rahmen eines Refactoring, weils halt doch irgendwo eleganter ist, aber bis dahin ...

... bin irgendwie baff, wie viele Leute sich zu dieser vorgerückten Stunde noch im Forum herumtreiben. :shock:

Verfasst: Samstag 5. Juli 2008, 01:00
von Karl
Pekh hat geschrieben:Könnte ich, aber an der Stelle hat das keinen praktischen Mehrwert. Vielleicht ändere ich das irgendwann mal im Rahmen eines Refactoring, weils halt doch irgendwo eleganter ist, aber bis dahin ...

... bin irgendwie baff, wie viele Leute sich zu dieser vorgerückten Stunde noch im Forum herumtreiben. :shock:
Ja, eigentlich sollte man Freitags um die Uhrzeit besoffen durch die Straßen ziehen :p

Verfasst: Samstag 5. Juli 2008, 01:13
von Pekh
Karl hat geschrieben: Ja, eigentlich sollte man Freitags um die Uhrzeit besoffen durch die Straßen ziehen :p
Besoffen sicherheitskritische Anwendungen schreiben macht doch viel mehr Spaß :lol:

Verfasst: Samstag 5. Juli 2008, 02:03
von cofi
Pekh hat geschrieben:Könnte ich, aber an der Stelle hat das keinen praktischen Mehrwert. Vielleicht ändere ich das irgendwann mal im Rahmen eines Refactoring, weils halt doch irgendwo eleganter ist, aber bis dahin ...
Naja der Mehrwert liegt in der Kapselung ;) Bring zusammen was zusammengehört! Besser wäre allerdings

Code: Alles auswählen

class A(object):
    x = {}
    @classmethod
    def set(cls):
        cls.x['key'] = 'value'

    
    @classmethod
    def get(cls):
        return cls.x
statt meinem fix zusammengezimmerten Code oben ...
Aber die Manipulation der Klassenvariablen scheint von ausserhalb wohl doch möglich zu sein ;)

Verfasst: Samstag 5. Juli 2008, 08:30
von Pekh
Wow. Die Lösung gefällt mir außerordentlich gut. Einer der Gründe, weshalb ich bei Python hängengeblieben bin, ist, daß es möglich ist gutaussehenden Code zu schreiben. Gutaussehender Code ist wie ein Gemälde an der Wand. :D

... ich werde das Refactoring wohl vorziehen müssen :D

Verfasst: Samstag 5. Juli 2008, 08:40
von numerix
Mannomann, da war es wohl für euch alle schon etwas spät ... :lol:

Die Lösung ist ganz einfach:

Code: Alles auswählen

t.objects={"A":3} 
in Zeile 15 erzeugt ein neues Attribut der Instanz t von T(), hat aber nichts mit dem gleichnamigen Klassenattribut zu tun.

Wenn du das ansprechen willst, musst du die Klasse voranstellen, keine Instanz der Klasse. Also Zeile 15 so:

Code: Alles auswählen

T.objects={"A":3} 
Dann klappt alles so wie du es wolltest und
t.t() liefert das gewünschte Ergebnis.

Verfasst: Samstag 5. Juli 2008, 08:45
von Pekh
Pekh hat geschrieben:Ja, das scheint tatsächlich die Lösung zu sein. Vielen Dank euch beiden. Habe das Problem jetzt dadurch umgangen, daß ich nicht t.objects sondern gleich T.objects von außen manipuliere.
Ja, das habe ich dann auch irgendwann herausgefunden. Aber danke :D

Trotzdem gefällt mir cofis Lösung im Moment am Besten ... ist ein bisschen mehr Schreibarbeit, sieht aber toll aus ...

Re: Klassenvariablen

Verfasst: Samstag 5. Juli 2008, 21:19
von Michael Schneider
Hallo Pekh!

Ehrlich gesagt habe ich beim Verfolgen des Threads im Nachhinein sehnsüchtig auf einen erlösenden Post wie den von Numerix gewartet, dank dafür. ;-)

Ich würde Numerix Erläuterung gern noch etwas ausführen:
Pekh hat geschrieben:Kann mir das jemand mal bitte erklären? Wenn ich statt des Dicts z.B. einen Integer hinterlege, funktioniert es. :?

Code: Alles auswählen

In [13]: class T(object):
   ....:     objects = {}
   ....:     
   ....:     def t(self):
   ....:         return T.objects
   ....:     
   ....:     

In [14]: t = T()

In [15]: t.objects={"A":3}

In [16]: t.t()
Out[16]: {}

In [17]: t.objects
Out[17]: {'A': 3}
Mit "t = T()" in Z. 9 erzeugst Du eine neue Instanz der Klasse T, die einen eigenen Namensraum besitzt. Durch Zuweisungen kannst Du Objekte an neue oder bereits existierende Namen binden:

Code: Alles auswählen

t.objects = {"A":3}     # bindet das dict an den Namen 'objects' der Instanz
T.objects = {"A":3}     # bindet das dict an den Namen 'objects' der Klasse
Man kann von außerhalb und innerhalb auf die Klassenattribute zugreifen, selbst auf die Privaten. Das ist also keineswegs ein workaround oder Trick, sondern grundlegendes Prinzip.

Häufig auftretender Grund für Verwirrung ist auch der Unterschied zwischen Objektänderung und Neubindung.
Wenn Du vor Zeile 11 das Attribut objects von t referenzierst, dann Prüft die Instanz t als erstes, ob der Name im builtin-Attribut __dict__ existiert, sonst delegiert sie die Anfrage an die Klasse weiter, die es dann findet.
Aber sobald Du in Zeile 11 den Namen objects der Instanz t neu bindest, wird der neue Name im __dict__ von t gespeichert und Du greifst bei der nächsten Referenzierung auf das neue Objekt zu, von dem die Klasse T natürlich nichts weiß.
Kleiner Test: ändere das Attribut objects doch mal, anstatt es neu zu binden, etwa so:

Code: Alles auswählen

# statt: t.objects={"A":3}
 t.objects.update({"A":3})
Grüße,
Michel