XtraNine hat geschrieben:Datenkapselung ist nicht das gleiche wie Zugriffsschutz.
Naja sagen wir es mal so: Die Philosophie der Objektorientierten Programmierung besteht doch
(unter anderem, da gehört noch viel mehr dazu) darin, das man Wichtige Attribute
(eigentlich alle nach C++/Java) dem Anwender nicht zugänglich macht und NUR Methoden zum Zugriff definiert,
Und wenn man Methoden zum Zugriff definiert, dann macht man die Attribute doch wieder zugänglich. Dem Anwender wirklich wichtige Attribute nicht zugänglich zu machen wäre komisch, weil sie ja offensichtlich wichtig sind.
Das ist eher die Philosophie von C++ und Java alle Attribute privat zu deklarieren und nicht universell auf OOP übertragbar. Und das ist in C++ und Java so weil dort im Objektmodell eine Unterscheidung zwischen Attributen und Methoden gemacht wird. Das ist in Python nicht der Fall. Dort sind einerseits alles Attribute und andererseits kann bei jedem Attributzugriff vordefinierter Code ausgeführt werden.
die auch genau überprüfen ob die übergebene Werte der Argument auch ordnungsgemäß sind (
Damit meine ich nicht Datentypen wie von dir gemeint…
Das mit dem überprüfen ob die richtigen Argumente übergeben wurden, fällt in Python sowieso in den allermeisten Fällen weg, weil es das Duck Typing aushebelt,
…da reden wir gerade an einander vorbei. Es geht um die übergebenen werte ob die richtig sind.)
Aber Werte sind in Python hauptsächlich "Verhalten". Wie willst Du das prüfen ohne letztendlich das übergebene Objekt so zu benutzen wie es später einmal verwendet werden soll!? Das geht nicht wirklich. Insbesondere bei Objekten deren Zustand sich durch das Benutzen verändert.
Da wirfst Du wieder Datenkapselung und Zugriffsschutz zusammen. Datenkapselung heisst, dass man auf interne Daten nicht zugreift, auch nicht wenn man dürfte.
Nicht wirklich
Datenkapselung heißt dass man die Daten vom Benutzer verbirgt und nicht zugänglich macht und nur über Spezielle Methoden darauf zurückgegriffen werden darf.
Nein, das ist Zugriffschutz. Wenn ich in C `struct`s erstelle und diese nur mit dazugehörigen Funktionen bearbeite und nicht direkt darin herumpfusche, dann betreibe ich auch Datenkapselung.
Wenn Datenkapselung zwingend Zugriffsschutz voraussetzen würde und OOP ohne Datenkapselung nicht geht, dann wäre in Python kein OOP möglich. Es ist aber sogar in C machbar, wenn auch etwas umständlich, weil die Sprache keine spezielle Unterstützung dafür anbietet.
Das dient (im trivialsten fall) zum Schutz vor flanschen Werteingaben. Oder ums genauer zu sagen; Es wird klar zwischen Daten (nicht zugänglich = Private) und Methoden unterschieden (öffentliche definierte Methoden = Public).
Wenn ich ein privates Attribut habe für das es einen öffentlichen Getter/Setter gibt, dann ist dieses Attribut de facto öffentlich. Damit ist die Unterscheidung überflüssig.
Aber die eigentliche Philosophie von OO ist das man Daten (Variablen, Attribute wie immer man das nenne will) klar trennt von den Methoden, weil ein Klasse, die in Abstrakter Form ein Objekt mit Eigenschaft darstellt.
Die eigentliche OO Philosophie spricht nicht von Daten und Methoden sondern von Objekten und Nachrichten. Man schickt einem Objekt eine Nachricht und bekommt ein Objekt als Antwort. Im Fall vom Kreis schicke ich einem Kreis-Objekt die Nachricht `radius` und bekomme ein Objekt zurück, welches sich wie eine Zahl verhält. Ob ich direkt ein fertiges Objekt aus dem Namensraum des Objektes bekomme oder etwas, das erst berechnet werden muss, entscheidet das Kreis-Objekt! Jedenfalls ist das in Python so. In C++ und Java gibt es die klare Unterscheidung zwischen Daten (Attribute) und Code (Methoden), das ist aber nicht gottgegeben und von OO so vorgeschrieben.
`radius` ist eine Eigenschaft von Kreisen und zwar eine die von öffentlichem Interesse ist.
Und wir wissen ja aus der Wirklichkeit das die Eigenschaften (im OO gleich Attribute) von Realen Objekten nicht direkt manipulierbar sind sondern nur über die zu Verfügung gestellten "Methoden".
Reale Objekte haben keine Methoden. Das scheinst Du zumindest unbewusst schon selbst so zu sehen, sonst hättest Du es nicht in Anführungszeichen gesetzt.
Beilspiel:
So ist es uns zum Beilspiel nicht möglich eine Information
(zB. wie das Wetter heute wahr) in ein Menschliches Gehirn des Gegenübers direkt zu Pflanzen. Das kann z.B. nur über die Methode
dein_Mund_sagt_etwas(self, information) zu
mein_ohr_hört_zu(self, information) geschehen oder durch die Methode
deine_hand_schreibt_was(self, information) zu
meine_augen_lesen_das(self, information).
Bei der Methode
mein_ohr_hört_zu und
meine_augen_lesen_das kommen dann noch diverse weitere Faktoren
(die wider durch interne Attribute, die nicht direkt manipulierbar sind, bestimmt werden) wie,
__hab_ich_lust_zuzuhören,
__ist_der_gegenüber_sympatischc ,
__fühle_ich_mich_heute_überhaupt_gut, etc xD Je nachdem wie die weiteren Faktoren ausfallen findet dann eine Informationsaufnahme statt
So, nach deinem Beispiel bzw. deiner Philosophie von Objektorientierter Programmierung würdest du folgendes machen:
__hab_ich_lust_zuzuhören = maxValue
__ist_der_gegenüber_sympatisch = maxValue
__fühle_ich_mich_heute_überhaupt_gut = maxValue
…
…
__Gehirn.append ("Schönes wettert heute wa?")
startDenkprozessEinleiten(...)
Ich hoffe ich konnte dir näher bringen worauf ich hinaus wollte bei meinen vorigen Post zu Thema OO und Klassendesign.
Nicht wirklich, weil Programmieren immer eine Abstraktion der Realität darstellt und der Programmierer bestimmen kann wo die Grenzen liegen.
Du hast auch eine Menge in Deinem Pseudocode weggelassen. Ich nehme an es geht um Attribute eines `Gehirn` Objektes. Dann würde man natürlich auch nach "meiner" Sicht von OOP Datenkapselung betreiben. Also Attribute die einen führenden Unterstrich haben, würde man von aussen nicht benutzen. Ausnahme: Man wüsste genau was man tut weil man die Interna kennt. Objekte vom Typ `Gehirnchirurg`, `Seelenklempter` und `Hypnotiseur` kämen da in Frage. (In C++ wären das `friend`s.)
Und es spielt eine Rolle ob es nur primitive getter und setter sind. Einfach zu sagen das ist schlechter Stil reicht nicht, das musst Du auch begründen. Und die Begründung von C++ greift bei Python nicht.
Eine Saubere Klasse in C++ ist ein Klasse die keinerlei zugriff auf Variabeln (Attribute) zulässt sondern nur den Zugriff über Methoden zulässt. Alles andere ist sehr schlechter Programmierstiel, was ich ja eben oben begründet habe aus der Sicht der eigentlichen Philosophie der Objektorientierten Programmierung.
Du hast es nicht wirklich begründet. Du hast nicht die Frage nach dem
warum beantwortet, sondern nur genauso dogmatisch gesagt man trennt in OO in private Attribute und öffentliche Methoden ein. Das ist in C++ so, aber nicht in Python. Oder jeder anderen Programmiersprache die das Objekt/Nachricht basierte Objektmodell implementieren. Es geht darum die interne Arbeitsweise eines Objekts für den Benutzer transparent zu machen. Das ist das warum. Und das können C++ und und Java bei öffentlichen Datenattributen nicht leisten.
Wenn Du in C++ folgenden Code hast
dann weisst Du ganz genau, dass direkt in den Speicher gegriffen wird um das `baz` Objekt aus dem `foo` Namensraum zu holen. Es ist also unmöglich das `baz` dynamisch aus anderen Werten berechnet wird. Wenn das zukünftig irgendwann einmal der Fall sein soll, dann ändert sich für den Benutzer die API von dem Objekt weil man dann eine Methode daraus machen muss.
Und genau aus dem Grund macht man in C++ alles private, weil das die einzige Möglichkeit ist, die Implementierung transparent zu machen.
Du kannst aber unmöglich sagen was in Python bei
passiert, ohne in den Quelltext zu schauen. Das ist absolut das Betriebsgeheimnis des `foo` Objekts. Es kann sein, das ein Objekt aus dem Namensraum geholt wird. Oder das im Namensraum ein Objekt unter dem Namen liegt, welches das Deskriptor-Protokoll implementiert und das Ergebnis erst von diesem Objekt erzeugt wird (Beispiel: property) oder das es so ein Objekt im Namensraum gar nicht gibt und die `__getattr__()` Methode ausgeführt wird. Also alles was bei `get_baz()` auch gemacht werden könnte.