Um Attributwerte (Objekteigenschaften) gegen Fehler abzusichern, überprüft man diese in Methoden. Diese Methoden heißen Setter zum Ändern von Attributwerten und Getter zum Abrufen von Daten. Um nun sicherzustellen, dass die Daten immer über diese Methoden geändert und abgerufen werden kappselt man die Attribute, d.h. man macht die Attribute privat. Dadurch kann nur noch in der Klasse auf die Attribute direkt zugegriffen werden, von außerhalb nur über die Setter und Getter.
In diesem Artikel lernst Du wie man Attributwerte mit set- und get-Methoden absichert, die Bedeutung der Datenkapselung mit public und private sowie das UML-Klassendiagramm kennen.
Leuchtmittel
werden folgende Eigenschaften für die Leuchtmittel definiert: Leistungsaufnahme P in W (Watt), Lichtstrom Φ in lm (Lumen). Berechnen kann man hieraus die Lichtausbeute η in lm/W (Lumen pro Watt).
class Leuchtmittel: def __init__(self, leistung = 2.5, lumen = 340): self.leistung = leistung self.lumen = lumen def __str__(self): return self.__class__.__name__ + f" {self.leistung} W, 🔆 {self.lumen} lm und η = {self.lumen/self.leistung} lm/W"
Lampe
Eine Wagenradlampe der Klasse Beleuchtung
besteht aus Objekten der Leuchtmittel. Wir erstellen nun ein Objekt:
class Beleuchtung: l1 = Leuchtmittel(2.5, 340) l2 = Leuchtmittel(3, 420) print(l1) print(l2) #Die Leistung wird mit einem fehlerhaften Wert manipuliert. l2.leistung = -42.0 print(l2)
Folgende Ausgabe wird erzeugt:
Leuchtmittel 2.5 W, 🔆 340 lm und η = 136.0 lm/W
Leuchtmittel 3 W, 🔆 420 lm und η = 140.0 lm/W
Leuchtmittel -42.0 W, 🔆 420 lm und η = -10.0 lm/W
Der Benutzer kann fehlerhafte Werte setzen wodurch nicht nur der Wert, sondern auch nachfolgende Berechnungen fehlerhaft sind.
Leuchtmittel
Wir ersetzen den sogenannten Modifier der Attribute in der Klasse Leuchtmittel
beschränkt. Diesen Vorgang nennt man Kapselung. Man schirmt die Attribute vom Zugriff aus anderen Klassen ab.
Die Änderung von gekapselten Werten erlaubt man dann nur noch in den sogenannten set-Methoden; für den Wertzugriff verwendet man get-Methoden. Der indirekte Zugriff auf die Leuchtmittelattribute erfolgt aus der Klasse Lampe
:
class Beleuchtung: l1 = Leuchtmittel(2.5, 340) print(l1) #Die Leistung wird mit fehlerhaft manipuliert. l1.setLeistung(-2.5) print(l1)
class Leuchtmittel: def __init__(self, leistung = 2.5, lumen = 340): self.setLeistung(leistung) self.lumen = lumen #setter und getter für Leistung def setLeistung(self, leistung): if leistung >= 0: self.__leistung = leistung #geschütztes Attribut else: print("Wert fehlerhaft, der Wert bleibt unverändert.") def getLeistung(self): return self.__leistung def __str__(self): return self.__class__.__name__ + f" {self.__leistung} W, 🔆 {self.lumen} lm und η = {self.lumen/self.__leistung} lm/W"
Modifier | Die Klasse selbst | Unterklassen | sonstige Klassen |
---|---|---|---|
private (zwei Unterstriche) | ✓ | ✗ | ✗ |
protected (ein Unterstrich) | ✓ | ✓ | ✗ |
public (kein Unterstrich) | ✓ | ✓ | ✓ |
Erstelle die Klasse Leuchtmittel und Beleuchtung.
Leuchtmittel
und Beleuchtung
. Programmiere alle Methoden wie im Eingangsbeispiel. Vergiss dabei nicht in der to-String-Methode auch die Lichtausbeute auszugeben.l2 = Leuchtmittel(-2, 340)
,l2 = Leuchtmittel(0, 340)
,l2 = Leuchtmittel("0", 340)
.__leistung
gegen diese Fehler ab.Mit Setter und Getter wird der Zugriff auf Variablen mitunter unlesbar. Betrachten wir hierzu folgendes Beispiel. In der Klasse Beleuchtung wird die Leistung von l3 mit den Werten von l1 und l2 berechnet.
class Beleuchtung: l1 = Leuchtmittel(2.5,340) l2 = Leuchtmittel(1.5,200) l3 = Leuchtmittel() #Die Leistung von l3 wird mit den Werten von l1 und l2 berechnet. l3.setLeistung(l1.getLeistung()+l2.getLeistung()) print(l3)
Durch Properties wird der Code wieder lesbarer. Wir können die Variablen verwenden als ob sie öffentlich wären, sind sie aber nicht.
class Leuchtmittel: def __init__(self, leistung = 2.5, lumen = 340): ... def setLeistung(self, leistung): ... def getLeistung(self): ... def __str__(self): ... #property leistung = property(getLeistung, setLeistung) class Beleuchtung: l1 = Leuchtmittel(2.5,340) l2 = Leuchtmittel(1.5,200) l3 = Leuchtmittel() #Die Leistung von l3 wird mit den Werten von l1 und l2 berechnet. l3.leistung = l1.leistung + l2.leistung print(l3)
Nenne die Klasse, welche auf ein private
Attribut Zugriff hat.
Wähle eine Antwort.
Nenne Vorteile der Kapselung.
Wähle zwei Antworten.
Finde die Anzahl der Fehler im folgenden Quelltext.
def setLeistung(self, __leistung): if leistung >= 0: self.leistung = leistung else: print("Wert fehlerhaft")
Finde die Anzahl der Fehler im folgenden Quelltext.
def __init__(self, leistung): self.leistung = leistung def getLeistung(self, leistung): return self.__leistung
Bestimme die zugehörige Konstruktormmethode, zum Konstruktoraufrufs2 = Schaf(alter = 20, gewicht = 23.3)
. Wähle zwei Antworten.
def __init__(self, gewicht, alter)
def __init__(gewicht=1.0, alter=1)
def __init__(self, alter, gewicht, c="C")
def __init__(self, 20, 3)
Beschreibe einen Konstruktor.
Wähle beliebig viele Antworten.
#Typeerror - fehlerhafte Werte lumen = "hell" x = lumen + 1 #ZerodivisionError lumen = 0 x = 4/lumen #Value ValueError lumen = -20 x = math.sqrt(lumen)
Fehlerhafte Syntax kann nicht ausgeführt werden. Aber auch wenn die Syntax korrekt ist, kann es bei der Ausführung des Quelltextes zu einem Fehler kommen. Dann werden sogenannte Exceptions ausgelöst. Je nach Fehlerart unterscheidet man verschiedene Exceptions.
Mit Hilfe dieser Exceptions lassen sich verschiedene Fehlermeldungen abfangen. Bei der Erzeugung von Objekten kann man nun mit try und except Fehler abfangen. Hierzu wird einerseits die Objekterzeugung in einen try- und except-Block geschrieben und in der set-Methode auf fehlerhafte Werte geprüft und ggf. eine Exception ausgelöst.
class Leuchtmittel: def __init__(self, leistung = None, lumen = None): self.setLeistung(leistung) self.lumen = lumen def setLeistung(self, leistung): if(isinstance(leistung, (int, float)) and leistung > 0): self.__leistung = leistung else: raise ValueError("fehlerhafte Werte") #property leistung = property(getLeistung, setLeistung) class Beleuchtung: try: l1 = Leuchtmittel(12,300) print(f"Objekt wurde erzeugt.") except ValueError as errormessage: print(f"Objekt wurde nicht angelegt: {errormessage}")
Die Schafe sollen mit set-get-Fähigkeiten und Exceptionhandling ausgestattet werden.
Schaf
mit set-get-Methoden.Schafherde
die neuen Methoden und Exceptions ausführlich. Lass für jede Exception eine Erklärung anzeigen.Ein männlicher Briefmark erlebte
Was Schönes, bevor er klebte.
Er war von einer Prinzessin beleckt.
Da war die Liebe in ihm erweckt.
Er wollte sie wieder küssen,
Da hat er verreisen müssen.
So liebte er sie vergebens.
Das ist die Tragik des Lebens!
Erweitere die Klasse Auto und Fuhrpark.
Auto
mit set- und get-Methoden.Auto
auf private
Fuhrpark
durch Aufrufe der set- und get-Methoden und teste so die Funktionalität der Klasse Auto
.Auto
mit zwei Konstruktormethoden, den Standardkonstruktor mit Initalwerten und einem Konstruktor mit Parameterliste.UML (engl. unified modeling language) ist eine grafische Modellierungssprache zur Spezifikation, Konstruktion und Dokumentation von Software-Teilen und anderen Systemen. UML besteht aus vielen Diagrammtypen. Ein Typ davon ist das Klassendiagramm.
Ein Klassendiagramm stellt eine Klasse übersichtlich und strukturiert dar. Es ist von der Form her rechteckig und besteht aus drei Teilen:
+
für public
und -
für private
) und Datentyp,
Man beachte, das statische Methoden und Attribute unterstrichen werden. Der Vorteil statischer Methoden liegt darin, dass sie ohne die Erzeugung eines Objekts aufrufbar sind: Auto.setMwSt(19.0);
. Nachteilig wirkt sich aus, dass der Speicher immer belegt wird.
Was das Klassendiagramm nicht sagt:
Auto |
- farbe : str - leistung : int - preis : float - mehrwertsteuer : float |
+ Auto (str farbe, int leistung, float preis) + setFarbe (str color) : void + setLeistung (int power) : void + setMwSt (float mwst) : void + getFarbe () : str + getLeistung () : int + getMwSt () : float + fahrenStrecke (int km) : void + tanken (int menge) : void |
Schreibe UML-Klassendiagramme.
Auto
.Fuhrpark
.Schaf
.Schreibe weitere Klassenpaare.
Neben den Klassenpaaren Schaf
und Schafherde
sowie Auto
und Fuhrpark
, gibt es weitere Klassenpaare.
Wohnmobil
und Campingplatz
.Pizza
und Menue
.Sensor
und Home
.In der Praxis werden Objektdaten häufig im JSON-Format geliefert. Sind diese Daten in einer Liste kann man beim Erzeugen der Objekte über das Dictonary iterieren und so übersichtlich die Objekte erzeugen.
class Schafherde: schafliste = [ {"name": "Alma", "alter": 2, "gewicht": 2.3}, {"name": "Schaun", "alter": 9, "gewicht": 17.4}, {"name": "Schaun", "alter": 9, "gewicht": 0} ]
Um nun auf die einzelnen Werte im Dictonary zuzugreifen, wird über die Liste iteriert und mit den Schlüsselwerten auf die einzelnen Objektwerte zugegriffen: Schaf(s["name"],s["alter"],s["gewicht"])
. Des weiteren wird das try-except-Konezpt bei der Erstellung verwendet, so dass nur einwandfreie Objekte erzeugt werden.
Die Anzeige der erzugten Objekte erfolt wie gewohnt über die for-Schleife. In diesem Fall wurde in der Klasse Schaf
eine to-String-Methode hinterlegt sowie eine nummerierte Ausgabe mit der Funktion enumerate(..)
erzeugt, so dass alle erzeugten Objekte nummeriert ausgegeben werden.
In der Praxis werden Objektdaten häufig im JSON-Format geliefert. Sind diese Daten in einer Liste kann man beim Erzeugen der Objekte über das Dictonary iterieren und so übersichtlich die Objekte erzeugen.
#Schafe als Objekt anlegen schafherde = [] for s in schafliste: try: schafherde.append(Schaf(s["name"],s["alter"],s["gewicht"])) except TypeError as errorMessage: print(f"Objekt nicht angelegt: {errorMessage}") except ValueError as errorMessage: print(f"Objekt nicht angelegt: {errorMessage}") except: print("Sonstige Fehler") #Schafherde anzeigen for i,s in enumerate(schafherde, start=1): print(i,s)
Mit Hilfe von Dictonaries (JSON-Format) lassen sich übersichtlich Objekte mit Hilfe von For-each-Schleifen erstellen. Man beachte dass man mit Hilfe der Schlüssel auf die einzelen Werte zugreifen kann.
Realisiere eine Bücherei in der Bücher mit Titel, Autor und Bewertung gespeichert werden sollen.
Book
und Library
. Book
die Attribute title
, author
, rating
hinzu sowie entsprechende set- und get-Methoden.Library
ein Dictonary namens booklist
mit drei Einträge wie bspw. booklist.add(new Book("Herr der Ringe", "J.R.R. Tolkien", 4.8));
hinzu und erzeuge drei Objekte.Die Firma BestSolution4IT hat einen Programmcode erhalten. Anhand der folgdenden Fragen soll sichergestellt werden, dass der Quellcode verstanden wurde. Ordne die korrekten Antworten zu.
class Schaf: def __init__(self, name, alter, gewicht): self.name = name self.alter = alter self.setGewicht(gewicht) def setGewicht(self, gewicht): gewicht = float(gewicht) if gewicht <= 0: raise ValueError("Gewicht unzulässig") else: self.__gewicht = gewicht class Schafherde: schafliste = [ {"name": "Alma", "alter": 2, "gewicht": 2.3}, {"name": "Schaun", "alter": 9, "gewicht": -17.4}, {"name": "Emil", "alter": 20, "gewicht": "vier"}, ] schafherde = [] for s in schafliste: try: schafherde.append(Schaf(s["name"],s["alter"],s["gewicht"])) except TypeError as errorMessage: print(f"Objekt nicht angelegt: {errorMessage}") except ValueError as errorMessage: print(f"Objekt nicht angelegt: {errorMessage}") except: print("Sonstige Fehler")
Was passiert, wenn das Gewicht eines Schafs kleiner oder gleich 0 ist?
Wähle eine Antwort.
Welche Aussage trifft auf self.__gewicht
zu?
Wähle eine Antwort.
Welche Methode prüft die Gültigkeit des Gewichts?
Wähle eine Antwort.
__init__()
setGewicht()
__str__()
validate()
Welche Art von Fehler tritt bei gewicht = float("vier")
auf?
Wähle eine Antwort.
SyntaxError
TypeError
NameError
ValueError
Wie wird ein neues Schaf korrekt erzeugt?
Wähle eine Antwort.
Schaf("Berta", "alt", "leicht")
Schaf("Berta", 3, 4.0)
Schaf()
Schaf(name="Berta", gewicht=3.5)
das Objekt, -e | Objekte haben Eigenschaften (engl. states) und Fähigkeiten (engl. behaviors). Diese werden in einer zugehörigen Klasse festgelegt. |
die Klasse, -n | Eine Klasse beschreibt, welche Eigenschaften und Fähigkeiten ein Objekt haben darf und stellt somit den Bauplan von Objekten bereit. |
die Methode, -en | Fähigkeiten von Objekten werden in Methoden beschrieben. |
das Attribut, -en | Eigenschaften von Objekten werden in Attributen (Variablen) festgelegt. |
der Modifier, ~ | legt die Sichtbarkeit von Eigenschaften und Fähigkeiten fest, also ob diese bspw. privat oder öffentlich zugänglich sind |
die Kapselung, - | die Sichtbarkeit der Attribute einer Klasse wird auf private gesetzt und so schirmt man die Attribute vom Zugriff aus anderen Klassen ab. |
die set-, get-Methoden, - | Methoden die die abgeschirmten Attribute setzen oder auslesen. |
der Konstruktor, -en | Methode welche die Initialisierung der Parameter bei Objekterzeugung ermöglicht |
das Dictonary | speichert Daten im Objektformat (JSON) |