Moin
kurze Frage bezüglich dem OO-Design. Man kann ja auf Attribute der Objekte direkt zugreifen. Sollte man dennoch getter und setter nutzen und entsprechende Methoden definieren?
So grundsätzlich mein ich
Danke und viele Grüße
Heiko
OOP und Datenkapselung
@arti73: Wenn Du triviale Getter und Setter für ein Attribut hast, dann ist es nicht wirklich gekapselt also machen die trivialen Getter und Setter nur unnötige Schreibarbeit. Wenn Du nicht-triviale Getter und Setter hast (oder zumindest einen von beiden), dann ist das eine Ermessensfrage ob man das über Properties oder Methoden regelt. Wobei ich mit Attributen hier jetzt immer ”Datenattribute” meine. Methoden sind ja auch Attribute. Für Methoden einer Klasse würde ich grundsätzlich eher keine Getter und Setter schreiben.
Ich meinte die Daten-Attribute, ja
In folgendem Beispiel wären das dann triviale, oder? Da würde ich mir das sparen.
Bei Datum hingegen macht es ggf. später Sinn abzufragen, ob das Datum in einem bestimmten Gültigkeits-Bereich liegt. Dann würd' ich da eine Setter-Methode später definieren. Oder sollte man das dann direkt für alle Attribute machen wegen einheitlichem Zugriff auf die Klasse.
Ich mag mir direkt ne vernünftige Linie angewöhnen...
Danke soweit
In folgendem Beispiel wären das dann triviale, oder? Da würde ich mir das sparen.
Bei Datum hingegen macht es ggf. später Sinn abzufragen, ob das Datum in einem bestimmten Gültigkeits-Bereich liegt. Dann würd' ich da eine Setter-Methode später definieren. Oder sollte man das dann direkt für alle Attribute machen wegen einheitlichem Zugriff auf die Klasse.
Ich mag mir direkt ne vernünftige Linie angewöhnen...
Danke soweit
Code: Alles auswählen
class Patenkind():
def __init__(self, vorname='', name='', geburt=datetime.date, nummer=0):
self.vorname = vorname
self.name = name
self.geburt = geburt
self.nummer = nummer
def setVorname(self, vorname=''):
self.vorname=vorname
def setName(self, name=''):
self.name = name
def setGeburt(self, geburt=datetime.date):
self.geburt = geburt
def setNummer(self, nummer=0):
self.nummer=nummer
[...]
Zuletzt geändert von Anonymous am Donnerstag 15. September 2016, 10:43, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
@arti73: Die Frage ist ob das von Deinem Empfinden her eher ein Datenattribut ist oder etwas wofür das Objekt eine Tätigkeit ausführen muss. Für mich wäre es ein Datenattribut und zwar *immer*. Wenn da später doch noch mal etwas dazu kommt, zum Beispiel eine Bereichsprüfung, dann wird aus dem Attribut entweder ein Property oder es gibt eine zusätzliche Methode zum setzen mit Bereichsprüfung, falls die noch weitere Daten benötigt die vom Aufrufer kommen.
Die ganzen Defaultwerte machen keinen Sinn. Insbesondere bei den Settern und der Wert bei `geburt` ist falsch. Das ist kein Datum sondern ein Typ dessen Exemplare ein Datum repräsentieren.
Die Frage bei Defaultwerten ist immer ob es Sinn macht wenn sie verwendet werden. Ist ein Patenkind das durch ``Patenkind()`` entstanden ist, also gar kein Argument bekommen hat, tatsächlich ein sinnvoller Wert? Ich wage das zu bezweifeln.
Ich würde da einfach nur das hier schreiben:
Namen von allem, ausser Konstanten und Klassen, werden in Python übrigens `klein_mit_unterstrichen` geschrieben. Also wenn Setter, dann `set_vorname` statt `setVorname`. An der Stelle kann man dann auch gleich mal über den Sinn vom Mischen verschiedener (natürlicher) Sprachen bei den Namen nachdenken. Allgemein und auch innerhalb von einem Namen.
Die ganzen Defaultwerte machen keinen Sinn. Insbesondere bei den Settern und der Wert bei `geburt` ist falsch. Das ist kein Datum sondern ein Typ dessen Exemplare ein Datum repräsentieren.
Die Frage bei Defaultwerten ist immer ob es Sinn macht wenn sie verwendet werden. Ist ein Patenkind das durch ``Patenkind()`` entstanden ist, also gar kein Argument bekommen hat, tatsächlich ein sinnvoller Wert? Ich wage das zu bezweifeln.
Ich würde da einfach nur das hier schreiben:
Code: Alles auswählen
class Patenkind(object):
def __init__(self, vorname, name, geburt, nummer):
self.vorname = vorname
self.name = name
self.geburt = geburt
self.nummer = nummer
Kapselung schaffst du in dynamischen Sprachen wie Python nicht durch Code sondern durch Dokumentation. Du dokumentierst welche Probleme sich wie mit deinem Code lösen lassen und verschweigst dabei die Module, Funktionen, Klassen, Methoden, Attribute usw. die ausschliesslich Teil der Implementation sind und nicht Teil der öffentlichen API.
Darüberhinaus kannst du langfristig rückwärtsinkompatible Änderungen ohnehin nicht vermeiden ohne dass es zur Lasten der Qualität geht. Es ist also viel wichtiger Wege zu finden mit solchen Änderungen umzugehen als Wege diese zu umgehen.
Darüberhinaus kannst du langfristig rückwärtsinkompatible Änderungen ohnehin nicht vermeiden ohne dass es zur Lasten der Qualität geht. Es ist also viel wichtiger Wege zu finden mit solchen Änderungen umzugehen als Wege diese zu umgehen.
Und falls noch Methoden dazu kommen sollen, kann man von so einem mit `namedtuple()` erstellten Typ auch eine Klasse ableiten. Vorteil dabei ist, dass man schon eine `__init__()` hat, eine nette `repr()`-Darstellung, und die andern Eigenschaften eines Tupels, wie Hash und Vergleich über die Attribute, so dass man solche Objekte zum Beispiel als Schlüssel in Wörterbüchern verwenden kann.