Klassenvariablen

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
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

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}
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

hast du das ``self`` vielleicht vergessen? ;)
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Nein. Ist ja schließlich eine Klassenvariable und keine Instanzvariable. Aber trotzdem danke.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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.
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

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.
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

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:
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

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:
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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 ;)
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

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
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

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.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

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 ...
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

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
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Antworten