managed attributes

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
joh#
User
Beiträge: 139
Registriert: Freitag 6. November 2009, 13:16

Hallo,
ich habe bei der v.2.6 folgendes versucht:

Code: Alles auswählen

>>> class CKl(object):
	def __init__(self):
		print"...Kontruktor..."
	def get_p1(self):
		print "...getter..."
		return self.__p1
	def set_p1(self, newval):
		self.__p1=newval
		print"...setter mit %d ..." % newval
	__p1=property(get_p1, set_p1)

	
>>> m1=CKl()
...Kontruktor...
>>> m1.p1

Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    m1.p1
AttributeError: 'CKl' object has no attribute 'p1'
>>> m1.__p1

Traceback (most recent call last):
  File "<pyshell#21>", line 1, in <module>
    m1.__p1
AttributeError: 'CKl' object has no attribute '__p1'
>>> 
d.h. ein privates Attribut __p1 definiert mit setter und getter.
Wie kann ich es denn nun von außen ansprechen? (s.o. geht ja nicht)

Griß
joh
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Wozu überhaupt solche trivialen getter und setter(und wenn dann benutzt man eher properties dafür)? Und wozu benutzt du zwei Unterstriche(was nicht privat im Java-Sinne bedeutet) wenn du sowieso von außen drauf zugreifen willst?

Ansonsten benutze _CKl__p1 statt __p1.
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

joh# hat geschrieben:[...] ein privates Attribut __p1 definiert mit setter und getter.
Wie kann ich es denn nun von außen ansprechen? [...]
Ich gehe jetzt mal davon aus, dass das eine rein akademische Frage ist. Explizit privat deklarierte Methoden und Attribute sollte man wirklich nicht von außen ansprechen, denn sonst kann man sich das auch gleich ganz schenken.

Such mal in der Dokumentation unter http://docs.python.org/reference/expressions.html nach "name mangling". Wenn du das Gelesene anwendest wirst du feststellen, dass du das Attribut mit m1._CKl__p1 ansprechen kannst. Den Folgefehler solltest du dir dann selber erklären können.
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

Du willst vermutlich folgendes:

Code: Alles auswählen

>>> class CKl(object):
	def __init__(self):
		print"...Kontruktor..."
	def get_p1(self):
		print "...getter..."
		return self._p1
	def set_p1(self, newval):
		self._p1=newval
		print"...setter mit %s ..." % newval
	p1=property(get_p1, set_p1)
(nicht wirklich getestet)
BlackJack

@joh#: Wenn man auf `__p1` normal zugreifen könnte, hättest Du ausserdem eine nette Endlosrekursion gebastelt. Eine Zuweisung an `__p1` würde `set_p()` aufrufen, was `__p1` etwas zuweist, was `set_p()` aufruft, was `__p1` etwas zuweist, was `set_p()` aufruft, …

"Managed attributes" heissen in Python übrigens "properties". Und doppelte führende Unterstriche sind in Python eher unüblich. Das ist zum Beispiel nützlich um Namenskollisionen bei Mehrfachvererbung zu vermeiden. Ansonsten gilt die Konvention, dass *ein* führender Unterstrich Implementierungsdetails kennzeichnet, die man von aussen nicht benutzen sollte.
joh#
User
Beiträge: 139
Registriert: Freitag 6. November 2009, 13:16

BlackJack hat geschrieben: "Managed attributes" heissen in Python übrigens "properties". Und doppelte führende Unterstriche sind in Python eher unüblich. Das ist zum Beispiel nützlich um Namenskollisionen bei Mehrfachvererbung zu vermeiden. Ansonsten gilt die Konvention, dass *ein* führender Unterstrich Implementierungsdetails kennzeichnet, die man von aussen nicht benutzen sollte.
Also ich habe
http://openbook.galileocomputing.de/pyt ... 9c0853ba45
(Tabelle 12.2 Namensschemata für öffentliche, private und geschützte Member ) gelesen.
joh
joh#
User
Beiträge: 139
Registriert: Freitag 6. November 2009, 13:16

bords0 hat geschrieben:Du willst vermutlich folgendes:

Code: Alles auswählen

>>> class CKl(object):
	def __init__(self):
		print"...Kontruktor..."
	def get_p1(self):
		print "...getter..."
		return self._p1
	def set_p1(self, newval):
		self._p1=newval
		print"...setter mit %s ..." % newval
	p1=property(get_p1, set_p1)
(nicht wirklich getestet)
ok, ich wollte einfach mal "versteckte setter/getter" testen, allerdings
führt ein
  • m1._CKl__p1
dann zu

Code: Alles auswählen

...getter...
...getter...
...getter...
. . . 
joh
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Das hat BlackJack dir doch schon vorausgesagt und erklaert.

EDIT: Das OpenBook taugt nichts, such mal im Forum danach.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

joh# hat geschrieben: ok, ich wollte einfach mal "versteckte setter/getter" testen, allerdings
führt ein
  • m1._CKl__p1
dann zu

Code: Alles auswählen

...getter...
...getter...
...getter...
. . . 
Tipp: Überleg mal, was das

Code: Alles auswählen

    return self.__p1
in deinem Code wohl bewirkt.
joh#
User
Beiträge: 139
Registriert: Freitag 6. November 2009, 13:16

Rebecca hat geschrieben:Das hat BlackJack dir doch schon vorausgesagt und erklaert.

EDIT: Das OpenBook taugt nichts, such mal im Forum danach.
ok, das mit dem OpenBook lesen war also keine so gute Idee...
Wie genau würde denn nun das dortige Beispiel "Konto" in
wohlgefälligem Python aussehen (das Beispiel an sich, fand ich schon
nicht schlecht, nur muß es ebene funktionieren) Vielleicht hat das
hier im Forum schon mal jemand 'übersetzt'?
joh
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

joh# hat geschrieben:ok, das mit dem OpenBook lesen war also keine so gute Idee...
Wie genau würde denn nun das dortige Beispiel "Konto" in
wohlgefälligem Python aussehen (das Beispiel an sich, fand ich schon
nicht schlecht, nur muß es ebene funktionieren) Vielleicht hat das
hier im Forum schon mal jemand 'übersetzt'?
joh
So:

Code: Alles auswählen

class Konto(object): 
    def __init__(self, inhaber, kontonummer, kontostand, 
                       max_tagesumsatz=1500): 
        self.inhaber = inhaber 
        self.kontonummer = kontonummer 
        self.kontostand = kontostand 
        self.max_tagesumsatz = max_tagesumsatz 
        self.umsatz_heute = 0    def geldtransfer(self, ziel, betrag): 
    # diese Methoden sind ok(bloß die Instanzvariablen müssten angepasst werden):    
    def einzahlen(self, betrag): 
        pass 
 
    def auszahlen(self, betrag): 
        pass 
 
    def zeige_konto(self): 
        pass
Die getter und setter sind in dem Beispiel überflüssig. Da es allerdings ein Beispiel ist, kann man sie trotzdem verwenden wenn man möchte. Ich habe allerdings den Eindruck, dass du noch nicht verstanden hast, warum dein Code nicht funktioniert.

Du definierst __p1 als property, in der setter-Funktion greifst du aber auf eben dieses __p1 wieder zu, wodurch die Funktion erneut aufgerufen wird. Also, definieren eine property als p1 und nicht als __p1.
joh#
User
Beiträge: 139
Registriert: Freitag 6. November 2009, 13:16

Darii hat geschrieben:So:
. . .
Danke, das funktioniert.
Darii hat geschrieben: Die getter und setter sind in dem Beispiel überflüssig. Da es allerdings ein Beispiel ist, kann man sie trotzdem verwenden wenn man möchte. Ich habe allerdings den Eindruck, dass du noch nicht verstanden hast, warum dein Code nicht funktioniert.
Das mit der (ungewollt erschaffenen) Rekursion ist jetzt schon verstanden.
Darii hat geschrieben: Also, definieren eine property als p1 und nicht als __p1.
Ich glaube die Leute aus dem OpenBook wollten sagen: "Greife nie direkt auf die Attribute eines Objekts zu, aber es geht trotzdem durch einen impliziten Aufruf einer setter/getter Methode kann dabei auch etwa die gleiche Sicherheit wie beim expliziten Methodenaufruf erreicht werden"
Dabei kam allerdings etwas Konfusion rein wegen der falschen Unterstriche.
Vorausgesetzt es verstößt nicht gegen den guten Python Stil wie würde so ein impliziter
Aufruf für

Code: Alles auswählen

k1.kontostand=23000
denn dann codiert
BlackJack

@joh#: Nur mal so sprachlich: Methoden sind auch Attribute von Objekten. Diese harte Trennung zwischen "das sind Daten" und "das ist Code" gibt es in Python nicht. Alles was an einen Namen gebunden wird, kann auch als Datum behandelt werden. Also zum Beispiel in Datenstrukturen gesteckt oder als Argumente übergeben werden. Alles sind Objekte; und einige sind halt aufrufbar und andere nicht.

``k1.kontostand = 23000`` würde man wahrscheinlich eher nicht schreiben, weil ein Konto normalerweise über die Operationen darauf manipuliert wird, und das setzen eines fixen Betrags ausser beim Anlegen in der Regel nicht vorkommen sollte. Konten werden durch Ein- und Auszahlungen manipuliert. Das Attribut ist also semantisch nur zum Abfragen da. Was nicht heisst, dass man das setzen durch `property()`\s verhindern muss. Es reicht das zu dokumentieren. Wem das zu "unsicher" ist, für den ist Python wahrscheinlich nicht die richtige Programmiersprache.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

joh# hat geschrieben:Ich glaube die Leute aus dem OpenBook wollten sagen: "Greife nie direkt auf die Attribute eines Objekts zu, aber es geht trotzdem durch einen impliziten Aufruf einer setter/getter Methode kann dabei auch etwa die gleiche Sicherheit wie beim expliziten Methodenaufruf erreicht werden"
Die vom Openbook haben einfach nur versucht unreflektiert Java-Konzepte auf Python zu übertragen. Ein trivialer getter/setter(der nichts weiter tut als den Wert selbst zuzuweisen) ist in Python unnötig, da man in Python, wenn es später nötig ist, transparent(d.h. ohne die Schnittstelle zu verändern) den Attributzugriff durch eine property ersetzen kann. Das geht ihn Java nicht, zudem gibt es Sachen wie JavaBeans Properties. Kurz: In Java muss man einfach quasi immer getter/setter verwenden.

Getter/setter, die nicht weiter tun als den Typ zu überprüfen sind in Python auch meist überflüssig, da wäre es besser gleich eine Sprache mit statischer Typisierung zu verwenden wenn einem das zu Heikel ist.
Antworten