Kapitel 9: Objektorientierung,...

43
Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung 1 Holger Karl Wintersemester 2016/2017 Inhaltsverzeichnis Inhaltsverzeichnis 1 Abbildungsverzeichnis 2 Liste von Definitionen u.ä. 2 9.1 Überblick ............................... 3 9.2 Verwandtschaft zwischen Dingen/Konzepten ........... 3 9.3 Verwandtschaft zwischen Klassen ................. 6 9.4 Vererbung in Python ........................ 12 9.5 Reflektion .............................. 23 9.6 Sichtbarkeit ............................. 27 9.7 getter/setter ............................. 29 9.8 Fehlerhafte Nutzung? ........................ 39 9.9 Gute Nutzung? Entwurf mit Klassen? ............... 40 1

Transcript of Kapitel 9: Objektorientierung,...

Page 1: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

Kapitel 9: Objektorientierung, VererbungGrundlagen der Programmierung 1

Holger Karl

Wintersemester 2016/2017

Inhaltsverzeichnis

Inhaltsverzeichnis 1

Abbildungsverzeichnis 2

Liste von Definitionen u.ä. 29.1 Überblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39.2 Verwandtschaft zwischen Dingen/Konzepten . . . . . . . . . . . 39.3 Verwandtschaft zwischen Klassen . . . . . . . . . . . . . . . . . 69.4 Vererbung in Python . . . . . . . . . . . . . . . . . . . . . . . . 129.5 Reflektion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239.6 Sichtbarkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279.7 getter/setter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299.8 Fehlerhafte Nutzung? . . . . . . . . . . . . . . . . . . . . . . . . 399.9 Gute Nutzung? Entwurf mit Klassen? . . . . . . . . . . . . . . . 40

1

Page 2: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.10 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . 41

Abbildungsverzeichnis

9.1 Linne’sche Klassifikation . . . . . . . . . . . . . . . . . . . . . . 4

9.2 Artikel-Klassifikation . . . . . . . . . . . . . . . . . . . . . . . . 4

9.3 Personen-Klassifikation . . . . . . . . . . . . . . . . . . . . . . 5

9.4 Klassenhierarchie in UML: Darstellung der is-a Relation . . . 6

9.5 Klassenhierarchie für Artikel: Daten in UML . . . . . . . . . . . 7

9.6 Speziellere Objekte sind eine Teilmenge der allgemeineren Ob-jekte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

9.7 Klassenhierarchie für Artikel: Neue Methoden . . . . . . . . . . 9

9.8 Klassenhierarchie für Artikel: Veränderte Methoden . . . . . . . 10

9.9 Kein Konstruktoraufruf der Oberklasse . . . . . . . . . . . . . . 14

9.10 Dokumentation lesen rettet Leben . . . . . . . . . . . . . . . . 25

9.11 With great power comes great responsibility . . . . . . . . . . . 28

9.12 Verinbarung einer Temperature-Klasse mit einer Property . . . 35

9.13 Setzen des Attributs, um den Wert der Property zu speichern . . 35

9.14 Nach Ende des Konstruktors . . . . . . . . . . . . . . . . . . . . 36

9.15 Klassen erlauben auch eine Verallgemeinerung . . . . . . . . . 42

2

Page 3: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

Liste von Definitionen u.ä. 3

Liste von Definitionen u.ä.

9.1 Definition (Vererbung: Terminologie) . . . . . . . . . . . . . . 119.2 Definition (Substitionsprinzip (Liskov)) . . . . . . . . . . . . . 119.3 Definition (Don’t repeat yourself (DRY)) . . . . . . . . . . . . . 199.4 Definition (Reflektion (Reflection)) . . . . . . . . . . . . . . . . 279.1 Bemerkung (Sichtbarkeit) . . . . . . . . . . . . . . . . . . . . . 299.5 Definition (Schnittstelle (Interface)) . . . . . . . . . . . . . . . 38

Page 4: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

4 Liste von Definitionen u.ä.

9.1 Überblick

9.1.1 Was bisher geschah

• FunktionenundKlassen erlaubendieWiederverwendung vonProgramm-code

• Aber es gibt keine Möglichkeit, vorhandene Funktionen/Klassen abzu-wandeln, auf Spezialfälle zuzuschneiden

9.1.2 Dieses Kapitel

• Wir entwicklen Klassen weiter und erlauben Modifikation und Adaptionder Funktionalität– Vererbung von Klassen und Polymorphie– Erfordert Überschreiben von Methoden

• Dies resultiert in Hierarchien von Klassen• Insgesamt: Konzept der objektorientierten Programmierung

– Ohne Vererbung: nur objektbasiert

9.2 Verwandtschaft zwischen Dingen/Konzepten

9.2.1 Programme reflektieren die Wirklichkeit

• Viele Programme haben etwas mit der Wirklichkeit zu tun– Be-/verarbeiten Daten, die tatsächliche Dinge beschreiben

• Tatsächliche Dinge sind oft klassifizierbar– Möglicherweise mit verschiedenen Sichtweisen

• Vorstellungen: ähnliche Dinge, allgemeinere Dinge, speziellere Dinge

9.2.2 Ähnlich, allgemeiner, spezieller

Vorüberlegungen:

• Zwei Dinge sind ähnlich wenn sie– ähnliche Daten haben; mit gleicher Struktur– ähnlich verarbeitet werden können

• Ein Ding ist spezieller als ein anderes Ding, wenn– mehr Wissen über das speziellere Ding gibt– besondere Verarbeitung möglich ist– besondere Fähigkeiten vorliegen

Page 5: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.2. Verwandtschaft zwischen Dingen/Konzepten 5

9.2.3 Allgemeiner/spezieller und Hierarchien

• Wenn Dinge in einer allgemeiner/spezieller Beziehung stehen, dann ineine Hierarchie einordnen?

• Je allgemeiner, desto weiter oben• Je spezieller, desto weiter unten

9.2.4 Hierarchien: Beispiel Lebewesen

Beispiel: Linnesche Taxonomy Abbildung 9.1

Abbildung 9.1: Linne’sche Klassifikation

9.2.5 Hierarchien: Waren bei Online-Buchhändler

Abbildung 9.2

Abbildung 9.2: Artikel-Klassifikation

9.2.6 Hierarchien: Personen an einer Uni

Abbildung 9.3

9.2.7 Klassifikation: Gemeinsamkeiten

• Klassifikation ist nützlich• Aber entscheidend: Gemeinsamkeiten identifizieren!

Page 6: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

6 Liste von Definitionen u.ä.

Abbildung 9.3: Personen-Klassifikation

– Zwischen Hominiden?– Geräten?– Werken?

9.2.8 Beispiel: Gemeinsamkeiten von Artikel, Werk, Buch, . . .

• Alle Artikel haben– Artikelnummer– Preis

• Alle Werke haben zusätzlich zu Artikel:– Ersteller– Titel

• Alle Bücher haben zusätzlich zu Werk:– Autor– Verlag– ISBN

• Alle Musikträger haben zusätzlich zu Werk:– Interpret– Liste von Musikstücken

9.2.9 Beispiel: Gemeinsamkeiten von Artikel, Werk, Buch, . . . (2)

Aber:

• Hat jeder Artikel einen Autor?• Hat jedes Werk einen Interpret?• . . . ?

Nein!

• Manche Daten nur ab einer bestimmten Spezialisierung sinnvoll

9.3 Verwandtschaft zwischen Klassen

Page 7: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.3. Verwandtschaft zwischen Klassen 7

9.3.1 Gemeinsamkeiten in Klassen fassen

Bisher wäre möglich:

• Je eine Klasse für Kinderbuch, Fachbuch, CD, DVD, . . .– Die Blätter der Hierarchie

• In jeder Klasse alle gemeinsamen Daten jeweils wieder neu aufschreiben

Nicht schön! Redundant! Fehleranfällig!

• Besser: Gemeinsamkeiten nur einmal aufschreiben!

9.3.2 Gemeinsamkeiten in Klassen fassen (2)

Also Idee:

• Eine Klasse, die Artikel darstellt• Eine weitere Klasse, die die zusätzliche Information für ein Buch hin-zufügt, Ausgangsdaten von Artikel übernimmt

• Eine weitere Klasse, die die zusätzliche Information für ein Hardcoverhinzufügt, Ausgangsdaten von Buch übernimmt

• usw. . .

9.3.3 Gemeinsamkeiten – Darstellung in UML

• Klasse B übernimmt Daten von Klasse A: Linie von B nach Amit Pfeilbei A– Genauer: Ein Objekt der Klasse B hat alle Attribute, die auch einObjekt der Klasse A hat

– Plus ggf. weitere

9.3.4 Gemeinsamkeiten – Darstellung in UML allgemein

Abbildung 9.4 zeigt beispielhaft die Darstellung der Verschwandschaftsbezie-hungen zwischen der Oberklasse und einer Unterklasse.

Abbildung 9.4: Klassenhierarchie in UML: Darstellung der is-a Relation

Page 8: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

8 Liste von Definitionen u.ä.

9.3.5 Gemeinsamkeiten – Darstellung in UML für Artikel

Abbildung 9.5: Klassenhierarchie für Artikel: Daten in UML

Visualisierung

Abbildung 9.5 zeigt die UML-basierte Visualisierung dieser Idee. BeachtenSie, dass nur die hinzugefügten Daten notiert werden.

Zustätzlich sind hier mehrere Unterklassen zu sehen. Diese zeigen jeweilsauf die Oberklasse. Eine Anordnung horizontal nebeneinander ist üblich unddeute eine Geschwister-artige Beziehung an.

9.3.6 Vererbung, is-a-Beziehung

• Terminologie: Vererbung– Die allgemeinere Klasse vererbt ihre Daten und Methoden an diespeziellere Klasse

• Weil Objekte der spezielleren Klasse alle Attribute der allgemeinerenKlasse haben, IST ein spezielleres Objekt auch ein allgemeineres Objekt– Das speziellere Objekt kann an Stelle eines allgemeineren Objektsverwendet werden; das fällt nicht auf

– Die sog. is-a Beziehung

9.3.7 is-a – Mengenbeziehung

Die spezielleren Objekte bilden eine Teilmenge der allgemeineren Objekte.Abbildung 9.6 illustriert das.

9.3.8 Warum nur Daten? Methoden!

• Klassen haben Methoden• Die werden natürlich auch übernommen

Page 9: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.3. Verwandtschaft zwischen Klassen 9

Abbildung 9.6: Speziellere Objekte sind eine Teilmenge der allgemeinerenObjekte

– Wenn Daten hinzukommen, werden die vorhandenen Methoden janoch funktionieren!

• Methoden hinzufügen?– Warum nicht!– Die is-a-Beziehung ist dadurch nicht verletzt

9.3.9 Neue, speziellere Methoden im Artikel-Beispiel

Was können diese Klassen?

• Jeder Artikel kann:– Information anzeigen– Preis um festen Prozentsatz verändern

• Jedes Buch kann zusätzlich:– Leseprobe anzeigen

• Jeder Musikträger kann zusätzlich:– Liste der Musikstücke ausgeben– Jeweils Hörprobe ausgeben

9.3.10 Allgemeinere Methoden im Artikel-Beispiel

Was ist mit den allgemeineren Methoden?

• Kann man den Preis eines Buches verändern?• Die Informationen eines Musikstückes anzeigen?

Warum nicht!

• Das Buch ist ein Artikel, also sollten diese Methoden anwendbar sein

9.3.11 Neue Methoden – UML

Visualisierung

In Abbildung 9.7 werden die zusätzlichenMethoden in den Unterklassen ange-geben.

Page 10: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

10 Liste von Definitionen u.ä.

Abbildung 9.7: Klassenhierarchie für Artikel: Neue Methoden

9.3.12 Methoden an Klasse anpassen?

• Die Information für ein Werk sollte den Titel enthalten? Für ein Gerätden Hersteller?

• Das könnte man mit neuen Methoden machen:– show_info_werk() in der Klasse Werk– show_info_geraet() in der Klasse Geraet

Nicht schön!

• Wird schnell unübersichtlich• Eigentlich will man doch auch von einem Gerät die Information?

9.3.13 Methoden verändern?

• Idee: Könnte die Klasse Werk, Geraet die Methode show_info() derKlasse Artikel verändern oder anpassen?– Eine abgewandelte Version der Methode, mit gleichem Namenangeben?

• Klassen (nicht nur Objekte) bilden Namensräume!– D.h., die Namen der Methoden der verschiedenen Klassen existie-ren ohnehin in verschiedenen Namensräumen

– Also ist es kein Problem, mehrere Methoden mit gleichem Namenin unterschiedlichen Klassen zu haben

– Also eigentlich: langweilig!

Page 11: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.3. Verwandtschaft zwischen Klassen 11

9.3.14 Veränderte Methoden – Aufruf

• Angenommen,wird implementieren eine andereMethodeshow_info()in Klasse Werk

• Was passiert bei Aufruf der Methode?– Bei Aufruf bei einem Objekt von Artikel: Die einfache Methodewird aufgerufen

– Bei Aufruf bei einem Objekt von Werk: Die neue Methode wirdaufgerufen

Was soll auch sonst passieren??

9.3.15 Veränderte Methoden – UML

Verändert eine Klasse eine Methode der allgemeineren Klasse, wird dieseMethode explizit im UML-Diagramm gezeigt

Abbildung 9.8: Klassenhierarchie für Artikel: Veränderte Methoden

Page 12: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

12 Liste von Definitionen u.ä.

9.3.16 Terminologie

Definition 9.1 (Vererbung: Terminologie). • Eine Klasse vererbt Datenoder Methoden an eine andere Klasse– Daten, Methoden stehen in Objekten der erbenden Klasse zur Ver-fügung

• Die vererbende Klasse heißt Oberklasse (super class) oder Basisklasse(base class)

• Die erbende Klasse heißt Unterklasse (sub class) oder abgeleitete Klasse(derived class)

• Wird bei Vererbung eine Methode verändert, so sagt man die Methodewird überschrieben

• Vererbung kann iterativ erfolgen– Eine Unterklasse kann Oberklasse einer weiteren Klasse sein

9.3.17 is-a, Kompatibilität, Substitution

Zur Betonung:

Definition 9.2 (Substitionsprinzip (Liskov)). Jedes Objekt einer Oberklassekann durch ein Objekt einer Unterklasse ersetzt werden – das sog. Substi-tionsprinzip. Objekte einer Unterklasse können den Platz von Objekten derOberklasse einnehmen. Sie können dabei durch überschriebene Methodenadaptiertes Verhalten zeigen.

Oder anders gesagt: Kann ein Programmmit Objekten einer Oberklassearbeiten, kann es auch ohne Änderung mit Objekten einer Unterklasse ar-beiten. Es wird diese Objekte als Instanzen der Oberklasse ansehen; durchÜberschreiben von Methoden kann trotzdem Funktionalität angepasst wer-den.

Umgekehrt funktioniert dies in der Regel nicht! Ein allgemeineres Objektkann im allgemeinen nicht benutzt werden, wenn ein spezielleres erwartetwird.

9.3.18 is-a, Kompatibilität (2)

• Die is-a Beziehung und Nutzung von Unterklasse-Objekten ist derentscheidende Punkt der Vererbung– Schreibersparnis bei Definition ist nett, aber nicht so wichtig

• Durch Schaffung neuer Klassen kann einem Programm Funktionalitäthinzugefügt werden, ohne dass der Rest des Programms geändert werdenmuss

• Beispiel:

Page 13: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.4. Vererbung in Python 13

– Kommen neue Artikelkategorien (Videospiele? Hausschuhe?) hin-zu, können die ohne Änderung mit verarbeitet werden

9.4 Vererbung in Python

9.4.1 Konkret: Vererbung in Python

• Schauen wir uns an, wie wir die Konzepte oben in Python umsetzenkönnen

9.4.2 Zunächst: Die Basisklasse Artikel

Eine ganz normale Klasse:

1 class Artikel:2 def __init__(self, artikelnummer, preis):3 self.artikelnummer = artikelnummer4 self.preis = preis5

6 def markup(self, percentage):7 """Konvention: Percentage == 1 lässt Preis unverändert"""8 self.preis *= percentage9

10 def show_info(self):11 return "Artikel {} zu {}€".format(self.artikelnummer,12 self.preis)13

14 def __str__(self):15 return self.show_info()16

17 a = Artikel("1234", 42.17)18 print(a)19 a.markup(1.1)20 print(a)

Artikel 1234 zu 42.17€Artikel 1234 zu 46.38700000000001€

Page 14: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

14 Liste von Definitionen u.ä.

9.4.3 Unterklasse Werk

• Ableiten: Unterklasse definieren, Oberklasse in Parameter angeben• Im Beispiel: Werk und Artikel identisch

1 class Werk(Artikel):2 pass

9.4.4 Unterklasse Werk: Konstruktor

1 class Artikel:2 def __init__(self, artikelnummer, preis):3 self.artikelnummer = artikelnummer4 self.preis = preis5

6 def show_info(self):7 return "Artikel {} zu {}€".format(self.artikelnummer,8 self.preis)9

10 class Werk(Artikel):11 def __init__(self, ersteller, titel):12 self.ersteller = ersteller13 self.titel = titel14

15 # Ein Werk wird mit vier Parametern initialisiert16 w = Werk("1234", 42.17, "Peter Müller", "Zur Bedeutung von GP1")

Fehler

• TypeError: __init__() takes 3 positional arguments but5 were given

• Das konnte nicht gehen: Konstruktor von Werk hat nicht genug Para-meter

9.4.5 Unterklasse Werk: Konstruktor (2)

Fix: Parameter hinzufügen

1 class Artikel:2 def __init__(self, artikelnummer, preis):3 self.artikelnummer = artikelnummer

Page 15: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.4. Vererbung in Python 15

4 self.preis = preis5

6 def show_info(self):7 return "Artikel {} zu {}€".format(self.artikelnummer,8 self.preis)9

10 class Werk(Artikel):11 def __init__(self, artikelnummer, preis, ersteller, titel):12 self.ersteller = ersteller13 self.titel = titel14

15 # Ein Werk wird mit vier Parametern initialisiert16 w = Werk("1234", 42.17, "Peter Müller", "Zur Bedeutung von GP1")17 print(w.show_info())

9.4.6 Fehler??

• AttributeError: ’Werk’ object has no attribute ’artikelnummer’• Das geht immer noch nicht? Das Attribute artikelnummer wird nichtgesetzt?

• Na, wie auch??– Der Konstruktor von Artikel würde das machen, aber den rufenwir ja nirgends auf

Remember

Explicit is better than implicit!

Abbildung 9.9: Kein Konstruktoraufruf der Oberklasse

9.4.7 Unterklasse Werk: Konstruktor der Oberklasse aufrufen

Wie kommen wir an Konstruktor von Artikel?

• Zugriff über Namensraum der Klasse!• Mit self als explizitem Parameter!

1 class Artikel:2 def __init__(self, artikelnummer, preis):

Page 16: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

16 Liste von Definitionen u.ä.

3 self.artikelnummer = artikelnummer4 self.preis = preis5

6 def show_info(self):7 return "Artikel {} zu {}€".format(self.artikelnummer,8 self.preis)9

10 class Werk(Artikel):11 def __init__(self, artikelnummer, preis, ersteller, titel):12 # Oberklassen-Konstruktor aufrufen:13 Artikel.__init__(self, artikelnummer, preis)14 self.ersteller = ersteller15 self.titel = titel16

17 # Ein Werk wird mit vier Parametern initialisiert18 w = Werk("1234", 42.17, "Peter Müller", "Zur Bedeutung von GP1")19 print(w.show_info())

9.4.8 Unterklasse Werk: Konstruktor der Oberklasse mit super aufru-fen

• Das funktioniert, aber ist nicht so schön: Der Klassenname Artikelwird mehrfach aufgeschrieben– Fehleranfällig, z.B. wenn man sich entscheidet, die Basisklasse zuwechseln

– Generell: Don’t repeat yourself (DRY)!– (Und funktioniert nicht bei multiple inheritance, siehe später)

• Daher neues Konstrukt: super()– Funktion, die Objekt der Oberklasse einer abgeleiteten Klasse lie-fert

– Zum Aufruf der entsprechenden Methoden– Nicht nur in __init__ nützlich (siehe z.B. Blog post)

9.4.9 Unterklasse Werk: Konstruktor der Oberklasse mit super aufru-fen (2)

1 class Artikel:2 def __init__(self, artikelnummer, preis):3 self.artikelnummer = artikelnummer4 self.preis = preis5

6 def show_info(self):7 return "Artikel {} zu {}€".format(self.artikelnummer,

Page 17: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.4. Vererbung in Python 17

8 self.preis)9

10 class Werk(Artikel):11 def __init__(self, ersteller, titel, artikelnummer, preis):12 # Oberklassen-Konstruktor aufrufen:13 super().__init__(artikelnummer, preis)14 self.ersteller = ersteller15 self.titel = titel16

17 # Ein Werk wird mit vier Parametern initialisiert18 w = Werk("Peter Müller", "Zur Bedeutung von GP1", "1234", 42.17)19 print(w.show_info())

(PT link)

Artikel 1234 zu 42.17€

9.4.10 Unterklasse Werk: Parameter des Oberklasse-Konstruktors mer-ken?

• Auch unschön: Im Konstruktor der Unterklasse muss man die Parameterder Oberklasse aufführen– Woher weiß ich das; fehleranfällig bei Änderung, . . .– Don’t repeat yourself!

• Besser: Nur eigene Parameter aufführen, Parameter der Basisklasse nuranonym durchreichen; egal wie beschaffen– *args und **kwargs!

• Typischer Programmierstil: *args und **kwargs durchreichen!

9.4.11 UnterklasseWerk: Parameter desOberklasse-Konstruktors durch-reichen

1 class Artikel:2 def __init__(self, artikelnummer, preis):3 self.artikelnummer = artikelnummer4 self.preis = preis5

6 def show_info(self):7 return "Artikel {} zu {}€".format(self.artikelnummer,8 self.preis)9

10 class Werk(Artikel):

Page 18: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

18 Liste von Definitionen u.ä.

11 def __init__(self, ersteller, titel, *args, **kwargs):12 # Oberklassen-Konstruktor aufrufen:13 super().__init__(*args, **kwargs)14 self.ersteller = ersteller15 self.titel = titel16

17 # Ein Werk wird mit vier Parametern initialisiert18 w = Werk("Peter Müller", "Zur Bedeutung von GP1", "1234", 42.17, )19 print(w.show_info())

9.4.12 UnterklasseWerk: Parameter desOberklasse-Konstruktors durch-reichen (2)

Oder noch schöner beim Instanziieren: Mit keyword-Argumenten

• Dann ist Reihenfolge egal!

1 class Artikel:2 def __init__(self, artikelnummer, preis):3 self.artikelnummer = artikelnummer4 self.preis = preis5

6 def show_info(self):7 return "Artikel {} zu {}€".format(self.artikelnummer,8 self.preis)9

10 class Werk(Artikel):11 def __init__(self, ersteller, titel, *args, **kwargs):12 # Oberklassen-Konstruktor aufrufen:13 super().__init__(*args, **kwargs)14 self.ersteller = ersteller15 self.titel = titel16

17 # Ein Werk wird mit vier Parametern initialisiert18 w = Werk(artikelnummer="1234", preis=42.17,19 ersteller="Peter Mueller", titel="Zur Bedeutung von GP1",)20 print(w.show_info())

9.4.13 Unterklasse Werk: show_info

• Objekt wird jetzt wohl richtig initialisiert• Aber nicht richtig ausgegeben• Wir müssen die Methode show_info noch überschreiben!

Page 19: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.4. Vererbung in Python 19

1 class Artikel:2 def __init__(self, artikelnummer, preis):3 self.artikelnummer = artikelnummer4 self.preis = preis5

6 def show_info(self):7 return "Artikel {} zu {}€".format(self.artikelnummer,8 self.preis)9

10 class Werk(Artikel):11 def __init__(self, ersteller, titel, *args, **kwargs):12 # Oberklassen-Konstruktor aufrufen:13 super().__init__(*args, **kwargs)14 self.ersteller = ersteller15 self.titel = titel16

17 def show_info(self):18 return "’{}’ von {} (Artikel {} zu {} €)".format(19 self.titel,20 self.ersteller,21 self.artikelnummer,22 self.preis)23

24 # Ein Werk wird mit vier Parametern initialisiert25 w = Werk(artikelnummer="1234", preis=42.17,26 ersteller="Peter Mueller", titel="Zur Bedeutung von GP1",)27 print(w.show_info())

9.4.14 Unterklasse Werk: show_info – Oberklasse mitbenutzen

• Oder in Werk.show_infoMethode Artikel.show_info nutzen– Don’t repeat yourself!

1 class Artikel:2 def __init__(self, artikelnummer, preis):3 self.artikelnummer = artikelnummer4 self.preis = preis5

6 def show_info(self):7 return "Artikel {} zu {}€".format(self.artikelnummer,8 self.preis)9

Page 20: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

20 Liste von Definitionen u.ä.

10 class Werk(Artikel):11 def __init__(self, ersteller, titel, *args, **kwargs):12 # Oberklassen-Konstruktor aufrufen:13 super().__init__(*args, **kwargs)14 self.ersteller = ersteller15 self.titel = titel16

17 def show_info(self):18 return "’{}’ von {} ({})".format(19 self.titel,20 self.ersteller,21 super().show_info())22

23 # Ein Werk wird mit vier Parametern initialisiert24 w = Werk(artikelnummer="1234", preis=42.17,25 ersteller="Peter Mueller", titel="Zur Bedeutung von GP1",)26 print(w.show_info())

9.4.15 Don’t repeat yourself

Definition 9.3 (Don’t repeat yourself (DRY)). Ein Prinzip der Software-Entwicklung: Every piece of knowledge must have a single, unambiguous,authoritative representation within a system. (Hunt & Thomas, PracticalProgrammer)

Bezieht sich auf viele Arten von Dokumenten: Quellcode, Dokumentation,Tests, Übersetzungssysteme, . . .

Gegensatz: Write everything twice (WET) (auch: we enjoy typing, wasteeverybody’s time).

9.4.16 str mitbenutzen?

Was wird hier ausgeben? Warum?

1 class Artikel:2 def __init__(self, artikelnummer, preis):3 self.artikelnummer = artikelnummer4 self.preis = preis5

6 def show_info(self):7 return "Artikel {} zu {}€".format(self.artikelnummer,8 self.preis)9

Page 21: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.4. Vererbung in Python 21

10 def __str__(self):11 return self.show_info()12

13 class Werk(Artikel):14 def __init__(self, ersteller, titel, *args, **kwargs):15 # Oberklassen-Konstruktor aufrufen:16 super().__init__(*args, **kwargs)17 self.ersteller = ersteller18 self.titel = titel19

20 def show_info(self):21 return "’{}’ von {} ({})".format(22 self.titel,23 self.ersteller,24 super().show_info())25

26 # Ein Werk wird mit vier Parametern initialisiert27 w = Werk(artikelnummer="1234", preis=42.17,28 ersteller="Peter Mueller", titel="Zur Bedeutung von GP1",)29 print(w)

(PT link)

’Zur Bedeutung von GP1’ von Peter Mueller (Artikel 1234 zu 42.17€)

Erläuterung

Hier geschieht folgendes. Die Funktion print versucht das Objekt w auszuge-ben. Dazu ruft sie, umeineZeichenketten-Repräsentation vonw zu bekommen,die Methode __str__ von w aufzurufen.

Und die gibt es natürlich! w ist ja vom Typ Werk. Werk selbst hat keine Metho-de __str__ definiert, aber da es ja alle Methoden von Artikel erbt, kommtdie von Artikel definierte Version __str__ zum Zug.

Der spannendePunkt ist nun,was beimAufruf self.show_info() in__str__passiert. Welche Version von show_info wird ausgeführt?

Das liegt daran, was self ist. Erinnern Sie sich: self ist ein Name für einObjekt; hier das Objekt, das auch unter dem Namen w (im globalen Scope)referenziert wird. Und das ist ein Objekt der Klasse Werk. Also wird im Na-mensraum dieser Klasse Werk nach einer Methode show_info gesucht. Diegibt es, also wird diese Methode Werk.show_info ausgeführt.

Als Teil dieserAusführung vonWerk.show_info()wird dannnochsuper.show_info()aufgerufen. Hier passiert dann das gleiche wie beim Aufruf des Konstruk-

http://www.pythontutor.com/visualize.html#code=class%20Artikel%3A%0A%20%20%20%20def%20__init__%28self%2C%20artikelnummer%2C%20preis%29%3A%0A%20%20%20%20%20%20%20%20self.artikelnummer%20%3D%20artikelnummer%0A%20%20%20%20%20%20%20%20self.preis%20%3D%20preis%0A%0A%20%20%20%20def%20show_info%28self%29%3A%0A%20%20%20%20%20%20%20%20return%20%22Artikel%20%7B%7D%20zu%20%7B%7D%E2%82%AC%22.format%28self.artikelnummer%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.preis%29%0A%0A%20%20%20%20def%20__str__%28self%29%3A%0A%20%20%20%20%20%20%20%20return%20self.show_info%28%29%0A%0Aclass%20Werk%28Artikel%29%3A%0A%20%20%20%20def%20__init__%28self%2C%20ersteller%2C%20titel%2C%20%2Aargs%2C%20%2A%2Akwargs%29%3A%0A%20%20%20%20%20%20%20%20%23%20Oberklassen-Konstruktor%20aufrufen%3A%20%0A%20%20%20%20%20%20%20%20super%28%29.__init__%28%2Aargs%2C%20%2A%2Akwargs%29%0A%20%20%20%20%20%20%20%20self.ersteller%20%3D%20ersteller%0A%20%20%20%20%20%20%20%20self.titel%20%3D%20titel%0A%0A%20%20%20%20def%20show_info%28self%29%3A%0A%20%20%20%20%20%20%20%20return%20%22%27%7B%7D%27%20von%20%7B%7D%20%28%7B%7D%29%22.format%28%0A%20%20%20%20%20%20%20%20%20%20%20%20self.titel%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20self.ersteller%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20super%28%29.show_info%28%29%29%0A%0A%23%20Ein%20Werk%20wird%20mit%20vier%20Parametern%20initialisiert%0Aw%20%3D%20Werk%28artikelnummer%3D%221234%22%2C%20preis%3D42.17%2C%0A%20%20%20%20%20%20%20%20%20ersteller%3D%22Peter%20Mueller%22%2C%20titel%3D%22Zur%20Bedeutung%20von%20GP1%22%2C%29%0Aprint%28w%29%0A&py=3
Page 22: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

22 Liste von Definitionen u.ä.

tors: super bestimmt die Oberklasse und sucht dort nach einer Methodeshow_info, die dann zur Ausführung kommt. super ist also nicht auf denKonstruktor beschränkt.

Insgesamt ist also der Ablauf der Methodenaufrufe bei print(w):

1. Artikel.__str__, weil vonprint beiw aufgerufen und vonArtikeland Werk vererbt,

2. Werk.show_info, weil self ein Name für ein Werk-Objekt ist undalso dieMethode show_info aus diesemNamensraum genommenwird,

3. Artikel.show_info, weil super in der Oberklasse nach show_infosucht.

9.4.17 Beispiel: is-a, Kompatibilität

Funktioniert das?

1 class A():2 pass3

4 class B(A):5 def f():6 print("f in B")7

8 a = A()9 a.f()

Nein!

Substitionsprinzip verletzt; Objekt a vom Typ A is-not-a B

9.4.18 Anmerkung: Dynamische Bindung

• Vorherige Folie zeigt Beispiel, wie die richtige Methode dynamisch,passierend auf dem vorliegenden Objekt, ausgewählt wird– Bindung: Auswahl der richtigen Methodenimplementation für Me-thodenaufruf

• In Python ist das der natürlich Vorgang• Andere Programmiersprachen kennen noch statische Bindung, was inder Regel zu Verwirrung führt

9.4.19 Beispiel: Dynamische Bindung in Klassenhierarchie

Was ist die Ausgabe?

Page 23: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.4. Vererbung in Python 23

1 class A:2 def __str__(self):3 return "A"4

5 class B(A):6 pass7

8 class B1(B):9 def __str__(self):10 return "B1"11

12 class B2(B):13 pass14

15 class C(A):16 def __str__(self):17 return "C"18

19 class C1(C):20 def __str__(self):21 return "C1"22

23 class C2(C):24 pass25

26 class C3(C):27 def __str__(self):28 return super().__str__()29

30 for l in [A(), B(), B1(), B2(), C(), C1(), C2(), C3()]:31 print(l, end=", ")

A, A, B1, A, C, C1, C, C,

1 pingo_title = "Was ist die Ausgabe?"2 pingo_type = "single"3 pingo_questions = ["A, A, B1, A, C, C1, C, C, ", "A, B, B1, B2, C, C1, C2, C2, ", "A, A, B1, B2, C, C1, C1, C3, ",4 ]5 pingo_duration = "120"6

7 %pingo

Page 24: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

24 Liste von Definitionen u.ä.

9.5 Reflektion

9.5.1 Veranschaulichung: isinstance und __class__, __name__

Zur Veranschalichung und Fehlersuche:

• Eingebaute Funktion isinstance– Argumente: Objekt und Klasse– Wahr, wenn Objekt ein Objekt der Klasse ist oder einer seiner Un-terklassen

• Vordefiniertes Attribut __class__ eines Objektes– Liefert eine Referenz auf die Klasse (als ein Klassenobjekt)

• Vordefiniertes Attribut __name__ einer Klasse– Liefert den Namen der Klasse als String– Also: c.__class__.__name__ ist Name der Klasse des Objektesc

9.5.2 Veranschaulichung: isinstanceund__class__, __name__–Bei-spiel

1 class A: pass2

3 class B(A): pass4

5 class B1(B): pass6

7 class B2(B): pass8

9 class C(A): pass10

11 class C1(C): pass12

13 class C2(C): pass14

15 class C3(C): pass16

17 for l in [A(), B(), B1(), B2(), C(), C1(), C2(), C3()]:18 print("{} von Klasse {}: ".format(l,19 l.__class__.__name__),20 end="")21 print("is-a A: {}; ". format(isinstance(l, A)), end="")22 print("is-a B: {}; ". format(isinstance(l, B)), end="")

Page 25: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.5. Reflektion 25

23 print("is-a C: {}". format(isinstance(l, C)))

<__main__.A object at 0x1011b0908> von Klasse A: is-a A: True; is-a B: False; is-a C: False<__main__.B object at 0x1017ad668> von Klasse B: is-a A: True; is-a B: True; is-a C: False<__main__.B1 object at 0x1017add68> von Klasse B1: is-a A: True; is-a B: True; is-a C: False<__main__.B2 object at 0x1017adda0> von Klasse B2: is-a A: True; is-a B: True; is-a C: False<__main__.C object at 0x1017ade10> von Klasse C: is-a A: True; is-a B: False; is-a C: True<__main__.C1 object at 0x1017adf60> von Klasse C1: is-a A: True; is-a B: False; is-a C: True<__main__.C2 object at 0x103000080> von Klasse C2: is-a A: True; is-a B: False; is-a C: True<__main__.C3 object at 0x103000a20> von Klasse C3: is-a A: True; is-a B: False; is-a C: True

9.5.3 Veranschaulichung: isinstanceund__class__, __name__–Bei-spiel mit __str__

Mit einer __str()__-Methode in A:

1 class A:2 def __str__(self):3 return "Objekt von {}; ".format(self.__class__.__name__)4

5 class B(A): pass6

7 class B1(B): pass8

9 class B2(B): pass10

11 class C(A): pass12

13 class C1(C): pass14

15 class C2(C): pass16

17 class C3(C): pass18

19 for l in [A(), B(), B1(), B2(), C(), C1(), C2(), C3()]:20 print(l, end="")21 print("is-a A: {}; ". format(isinstance(l, A)), end="")22 print("is-a B: {}; ". format(isinstance(l, B)), end="")23 print("is-a C: {}". format(isinstance(l, C)))

Objekt von A; is-a A: True; is-a B: False; is-a C: False

Page 26: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

26 Liste von Definitionen u.ä.

Objekt von B; is-a A: True; is-a B: True; is-a C: FalseObjekt von B1; is-a A: True; is-a B: True; is-a C: FalseObjekt von B2; is-a A: True; is-a B: True; is-a C: FalseObjekt von C; is-a A: True; is-a B: False; is-a C: TrueObjekt von C1; is-a A: True; is-a B: False; is-a C: TrueObjekt von C2; is-a A: True; is-a B: False; is-a C: TrueObjekt von C3; is-a A: True; is-a B: False; is-a C: True

9.5.4 Beginn der Klassenhierarchie: object

Wo kommen die Methoden wie __str__, __eq__ etc. her?

• Waren bei jedem Objekt verfügbar• Müssten die nicht aus einer Oberklasse kommen?

Oberste Oberklasse: object

Ja!

• Jede Klasse hat eine Oberklasse object• Es muss nicht explizit von dieser ererbt werden

– (Explicit is better than implicit. . . ??)• Damit: isinstance(o, object) == True für jedes Objekt

9.5.5 Methoden, Attribute von object ?

Und was kann object? Wie findet man die Methoden heraus?

• Option 1: Dokumentation lesen• Option 2: Die Klasse fragen!

Abbildung 9.10: Dokumentation lesen rettet Leben

9.5.6 dir einer Klasse, eines Objektes

• Eingebaute Funktion: dir

Page 27: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.5. Reflektion 27

• Anwendbar auf Klassen, Objekte• Gibt die bekannten Attribute als Liste zurück

1 print("Verzeichnis der Klasse object:")2 print(dir(object))3

4 class C:5 def bla(): pass6

7 c = C()8 # Verzeichnis eins Objekts der Klasse C9 print(dir(c))10 # Gibt es eine Methode hallo in Klasse C?11 print("hallo" in dir(C))

Verzeichnis der Klasse object:[’__class__’, ’__delattr__’, ’__dir__’, ’__doc__’, ’__eq__’, ’__format__’, ’__ge__’, ’__getattribute__’, ’__gt__’, ’__hash__’, ’__init__’, ’__le__’, ’__lt__’, ’__ne__’, ’__new__’, ’__reduce__’, ’__reduce_ex__’, ’__repr__’, ’__setattr__’, ’__sizeof__’, ’__str__’, ’__subclasshook__’][’__class__’, ’__delattr__’, ’__dict__’, ’__dir__’, ’__doc__’, ’__eq__’, ’__format__’, ’__ge__’, ’__getattribute__’, ’__gt__’, ’__hash__’, ’__init__’, ’__le__’, ’__lt__’, ’__module__’, ’__ne__’, ’__new__’, ’__reduce__’, ’__reduce_ex__’, ’__repr__’, ’__setattr__’, ’__sizeof__’, ’__str__’, ’__subclasshook__’, ’__weakref__’, ’bla’]False

9.5.7 Attribute inspizieren: getattr

Was wissen wir über bla?

• Eingebaute Funktion getattr liefert Information über Attribute einerKlasse, eines Objektes

1 class C:2 def bla(): pass3

4 c = C()5 print(getattr(C, ’bla’))6 print(getattr(c, ’bla’))

<function C.bla at 0x100797a60><bound method C.bla of <__main__.C object at 0x1007b0a90>>

Anmerkung: Funktion vs. bound method

Python unterscheidet intern zwischen einer reinen Funktion (function) undeiner Funktion, die als Methode zu einem Objekt gehört (bound method).Dieser Unterschied ist für uns hier zunächst nicht weiter wichtig.

Page 28: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

28 Liste von Definitionen u.ä.

9.5.8 Attribut hinzufügen: setattr

Angenommen, wir möchten einer Klasse nachträglich eine Methode hinzufü-gen:

1 class C: pass2

3 def f(self):4 print("Hallo")5

6 setattr(C, "hallo", f)7 # oder auch knapper: C.hallo = f8 c = C()9 c.hallo()

Hallo

9.5.9 Insgesamt: Reflektion

Hier betrachtete Funktionen, Attribute sind Beispiele für Reflektion

Definition 9.4 (Reflektion (Reflection)). Reflektion ist die Fähigkeit einesProgramms, seine eigene Struktur und die Struktur seiner Daten zur Laufzeitzu untersuchen (introspection) und ggf. zu modifizieren (modification).

Reflektion wird häufig zur Fehlersuche, Testen, Bewertung der Leistungs-fähigkeit, Integration ungünstig entworfener Klassenhierachien, oder auto-matischer Dokumentationserstellung benutzt.

Introspection steht in vielen objektorientierten Programmiersprachenzur Verfügung. Modification ist meist nur in dynamischen, interpretiertenSprachen vollständig vorhanden.

Mehr Details in VL GP2.

9.6 Sichtbarkeit

9.6.1 Zugriff auf Attribute, Methoden?

• Wer darf auf Attribute und Methoden eines Objektes zugreifen?• Einfach: Jeder, der eine Referenz auf das Objekt hat!

Page 29: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.6. Sichtbarkeit 29

• Sinnvoll?– Sollte jeder Nutzer einer Klasse beliebig Daten ändern?

• Beispiel: Binärbaum– Nicht-triviale Struktur– Vertrauen wir dem Nutzer des Binärbaums, die Struktur richtig zubehandeln?

9.6.2 Optionen? Öffentlich vs. privat

• Option 1:– Nur manche Methoden, Attribute einer Klasse öffentlich zugänglichmachen

– Andere Methoden, Attribute können nur von Methoden der Klasseselbst benutzt werden (privateMethoden, Attribute)

• Option 2:– Alles öffentlich zugänglich– We are all consenting adults

• Option 3 (Zwischenweg):– Im Prinzip öffentlich, aber mit Hinweisen an Nutzer

9.6.3 Python: Hinweise an Nutzer durch Namenskonvention

• Python wählt Option 3• Hinweise durch Konvention bei Namensgebung• Konvention: Führender Unterstrich

– Methoden, Attribute mit _ zu Beginn sollten vom Nutzer einerKlasse nicht direkt aufgerufen, gelesen, verändert werden

– Aber der Nutzer kann das schon, wenn er denkt, er weiß was er tut. . .

9.6.4 With great power comes great responsibility

Abbildung 9.11: With great power comes great responsibility

9.6.5 Sichtbarkeit

• Formal: Programmiersprachen haben unterschiedliche Ansätze zu Sicht-barkeit von Methoden, Attributen

Page 30: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

30 Liste von Definitionen u.ä.

Bemerkung 9.1 (Sichtbarkeit). Pythonhat ein sehr offenesModell von Sicht-barkeit – der Programmierer hat hier die Verantwortung, sinnvoll mit diesenMöglichkeiten umzugehen.

Andere Programmiersprachen haben ein elaboriertes System einge-schränkten Zugriffs auf Attribute und Methoden. Das ist manchmal nützlich,macht die Sprachen und das Objektmodell aber deutlich komplizierter.

Wir schauen uns das bei Java noch genauer an.

9.7 getter/setter

9.7.1 Zugriff auf Attribute

Frage: Gibt es Attribute eines Objektes, die an sich für den Nutzer einer Klassenicht unmittelbar nützlich sind?

• Bei lesendem Zugriff:– Die aufbereitet werden müssen?– Für die Statistiken geführt werden sollen? (Z.B. Anzahl Zugriff)

• Bei schreibendem Zugriff:– Auf sinnvolle Werte prüfen?– Bei denen mehrere Werte zueinander konsistent gehalten werdenmüssen?

– Für die Statistiken geführt werden sollen? (Z.B. Anzahl Zugriff)

9.7.2 Zugriff auf Attribute: Beispiele

• Beispiel: Klasse Studenten– Attribut Matrikelnummer (neben Name, Vorname, . . . )– Matrikelnummer hat Prüfziffer – nur korrekte Matrikelnummerakzeptieren

• Beispiel: Klasse Datum– Attribute: Tag, Monat, Jahr– Schreibender Zugriff: Tag=31 nicht in allen Monaten sinnvoll; Kon-sistenz prüfen

• Beispiel: Klasse Temperatur– Attribut: Temperatur, in Kelvin– Lesender/schreibender Zugriff auf Temperatur, in Grad Celsius– Ist das ein neues Attribut? Oder nur umrechnen? Gleiche Syntax?

Page 31: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.7. getter/setter 31

9.7.3 Naiver Ansatz: Nach Attribut-Zugriff, Methodenaufruf vorschrei-ben

• Eine naive Idee: Nutzer der Klasse aufgefordert, nach Attributzugriffeine Methode aufzurufen– Die dann ggf. Fehlermeldungen liefert

1 class C:2 """Invariante: Attribut x darf nur ungerade Zahlen enthalten"""3 def __init__(self):4 self.x = 175

6 def repair(self):7 # check x is odd8 if x % 2:9 return "Fehler"10

11 c = C()12 c.x = 213 c.repair()

Absurd!

• Zu eingeschränkt• Fehleranfällig wegen vergesslicher Programmierer

9.7.4 Nötig: Attribute hinter Methoden verbergen

• Per Konvention: Attribut bekommt einen Unterstrich vorangestellt– Sollte also nicht direkt benutzt werden

• Dann aber (typischerweise) nötig:– Methode zum Lesen des Attributs (get)– Methode zum Schreiben des Attributs (set)

Pro Attribute: getter und setter

• Pro solch geschütztem Attribut: eine sog. getter, eine setter Methode• Ggf. auch eine delete-Methode

9.7.5 getter und setter – Beispiel Student

1 class Student:2 def __init__(self):

Page 32: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

32 Liste von Definitionen u.ä.

3 # Achten Sie auf Unterstrich:4 self._matrikelnummer = None5

6 def get_matrikelnummer(self):7 # Keine besonderen Vorkehrungen beim Lesen nötig8 return self._matrikelnummer9

10 def set_matrikelnummer(self, value):11 if value hat richtige Pruefziffer:12 self._matrikelnummer = value13 return None14 else:15 return "Error"16

17 s = Student()18 # So:19 s.set_matrikelnummer(1234)20 # Nicht so - möglich, aber dringend abgeraten:21 s._matrikelnummer = 1234

Anmerkung: Fehlerbehandlung

Vorsicht, die Fehlerbehandlung in diesen Beispiel ist nicht praktikabel. Wirbrauchen dazu noch das Konzept der Exceptions – siehe nächstes Kapitel!

9.7.6 getter und setter – Beispiel Temperatur

Temperatur-Beispiel folgt grob dieser Webseite.

1 class Temperature:2 def __init__(self, temp=0):3 # rufe setter auch uns Methode der Klasse auf:4 self.set_temperature(temp)5

6 def get_temperature(self):7 return self._temperature8

9 def set_temperature(self, value):10 if value < 0:11 return "Error"12 else:13 self._temperature = value14

Page 33: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.7. getter/setter 33

15 t1 = Temperature(17)16 print(t1.get_temperature())17 t1.set_temperature(4242)18 print(t1.get_temperature())19 t1.set_temperature(-99)20 print(t1.get_temperature())

1742424242

9.7.7 getter und setter – Beispiel Temperatur: Scheinattribute hinzufü-gen

• Grad Celsius zusätzlich zu Kelvin?• Getter und setter für Celsius

– Aber wir nutzen nur ein Temperatur-Attribut!

1 class Temperature:2 def __init__(self, temp=0):3 # rufe setter auch uns Methode der Klasse auf:4 self.set_temperature(temp)5

6 def get_temperature(self):7 return self._temperature8

9 def set_temperature(self, value):10 if value < 0:11 return "Error"12 else:13 self._temperature = value14

15 # Ein weiteres getter/setter-Paar:16 def get_celsius(self):17 return self.get_temperature() - 27318

19 def set_celsius(self, value):20 return self.set_temperature(value + 273)21

22 t1 = Temperature(17)23 print(t1.get_temperature())24 t1.set_celsius(100)

Page 34: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

34 Liste von Definitionen u.ä.

25 print("In Kelvin:", t1.get_temperature())26 print("In Celsius:", t1.get_celsius())

17In Kelvin: 373In Celsius: 100

9.7.8 Getter und Setter – syntaktisch schöner?

• Getter und Setter-Methoden sind extrempraktisch für Klassenentwickler• Aber für Klassennutzer nicht schön zu benutzen

– Eigentlich will man die Attribute wie gewohnt nutzen ohne Me-thoden aufzurufen

– Beispiel:* t1.temperature = 17* print(t1.temperature)

• Wie üblich: wichtige Sonderfälle verdienen Unterstützung durch Spra-che

9.7.9 Getter und Setter: Property

• Python unterstützt das getter/setter-Konzept explizit durch den Proper-ty-Mechanismus– Zen: Explicit is better than implicit!

• Idee:– Wir koppeln explizit ein Attribut einer Klasse an eine Methode zumLesen, eine andere Methode zum Schreiben

– Wird dann lesen/schreibend auf Attribute zugegriffen, werden statt-dessen diese Methoden aufgerufen

• Damit: Nutzung des Attributs syntaktisch wie zuvor; getter/setter fürNutzer nicht sichtbar (transparent)!

9.7.10 Getter und Setter: Property – Beispiel Temperature

1 class Temperature:2 def __init__(self, temp=0):3 # auch Methoden der Klasse greifen normal auf das Attribut zu:4 self._temperature = temp5

6 def get_temperature(self):7 print("Lesender Zugriff")8 return self._temperature9

Page 35: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.7. getter/setter 35

10 def set_temperature(self, value):11 print("Schreibender Zugriff")12 if value < 0:13 return "Error"14 else:15 self._temperature = value16

17 # Vereinbare Attribut temperature als eine Property:18 temperature = property(get_temperature,19 set_temperature)20

21 t1 = Temperature(17)22 print(t1.temperature)23 t1.temperature = 4224 print(t1.temperature)

Lesender Zugriff17Schreibender ZugriffLesender Zugriff42

Visualiserung, Ablauf

1. Vereinbarung der KlasseWas passiert bei diesem kleine Programm? Die erste Anweisung ist dieVereinbarung der Klasse (Anweisung class, Zeile 1). Nach Ausführungdieser Anweisung ist die Klasse Temperature im globalen Namens-raum bekannt. Sie hat vier Attribute: die drei Methoden __init__,get_temperature, und set_temperature sowie eine propertytemperature. Abbildung 9.12 illustriert das.Wichtig ist hier zu verstehen, dass beim Definieren der Klasse die An-weisungen im Body der Klasse ausgeführt werden. Also neben den dreiAnweisungen def für die Definition der Methoden auf die Zuweisung anden Namen temperature, dem eine property zugewiesen wird alsRückgabewert der eingebauten Funktion property (genau genommenliefert diese Funktion ein Objekt der eingebauten Klasse property).

2. Ausführung des KonstruktorsIm Konstruktor wird in Zeile 4 auf die Property temperature schrei-bend zugegriffen. Vereinbarungsgemäß (per Anweisung in Zeile 18, 19)wird dazu die Methode set_temperature aufgerufen. In Zeile 15 wirddann dem gerade initialisierten Objekt (durch self referenziert) ein(ganz normales) Attribut _temperature hinzugefügt. Abbildung 9.13

Page 36: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

36 Liste von Definitionen u.ä.

Abbildung 9.12: Verinbarung einer Temperature-Klasse mit einer Property

zeigt den Zustand des Programms unmittelbar vor Rückkehr des erstenAufrufs des setters.

Abbildung 9.13: Setzen des Attributs, um den Wert der Property zu speichern

Zusätzlich sieht man noch die Ausgabe Schreibender Zugriff imOutput-Fenster rechts oben.

3. Nach Ende des KonstruktorsIn Abbildung 9.14 ist der Zustand nach Rückkehr des Konstruktors ge-zeigt. Es gibt ein Temperature-Objekt, das im globalen Scope durchden Namen t1 referenziert wird. Dieses Objekt hat ein einziges Datum,das Attribute _temperature (ja, mit Unterstrich!).

4. Am Ende der ersten getter-AufrufsAls letzten Schritt schauen wir noch den ersten Aufruf der getter-Methode get_temperature an. Das ist ein recht unspannender Teil:

Page 37: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.7. getter/setter 37

Abbildung 9.14: Nach Ende des Konstruktors

Beim Zugriff auf t1.temperature in Zeile 22 wurde die Methodeget_temperaturemit self is t1 aufgerufen. Entsprechend greiftget_temperature dann auf das Attribut _temperature von selfganz normal zu und macht den Wert zu ihrem Rückgabewert.

Anmerkung: Zugriff auf _temperature

Das Attribut _temperature ist ein völlig normales Attribut. Über eine Ob-jektreferenz t1 könnte man ohne weiteres auf t1._temperature zugreifen.Aber da dieses Attribut ja mit einem Unterstrich beginnt, macht man das alsanständiger Programmierer natürlich nicht!

Anmerkung: Namen

Nur um das klar zu stellen: Die Namen der Property und der setter und getterMethoden können beliebig gewählt werden. Das muss nicht, wie in diesemBeispiel, irgendwie dem Klassennamen entsprechen. Dazu noch ein Beispiel,in dem wird eine weitere Property celsius hinzufügen.

Allerdings bietet es sich an, Konventionen einzuhalten und etwas get_...und set_... für die Methodennamen zu nutzen. Denken Sie an jemanden,der Ihren Code lesen muss! (Principle of least astonishment)

9.7.11 Weitere getter/setter: Celsius

1 class Temperature:2 def __init__(self, temp=0):3 # auch Methoden der Klasse greifen normal auf das Attribut zu:4 self._temperature = temp

Page 38: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

38 Liste von Definitionen u.ä.

5

6 def get_temperature(self):7 print("Lesender Zugriff")8 return self._temperature9

10 def set_temperature(self, value):11 print("Schreibender Zugriff")12 if value < 0:13 return "Error"14 else:15 self._temperature = value16

17 # Vereinbare Attribut temperature als eine Property:18 temperature = property(get_temperature,19 set_temperature)20

21 # Eine zweite Property:22 def get_celsius(self):23 return self._temperature - 27324

25 def set_celsius(self, val):26 self._temperature = val + 27327

28 celsius = property(get_celsius, set_celsius)29

30 t1 = Temperature(273)31 print(t1.celsius)

0

9.7.12 Ablauf – Verständnisfrage

Was passiert hier, warum?

1 class Temperature:2 def __init__(self, temp=0):3 # auch Methoden der Klasse greifen normal auf das Attribut zu:4 self._temperature = temp5

6 # Vereinbare Attribut temperature als eine Property:7 temperature = property(get_temperature,8 set_temperature)

Page 39: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.7. getter/setter 39

9

10 def get_temperature(self):11 print("Lesender Zugriff")12 return self._temperature13

14 def set_temperature(self, value):15 print("Schreibender Zugriff")16 if value < 0:17 return "Error"18 else:19 self._temperature = value20

21 t1 = Temperature(273)

9.7.13 Diskussion: Getter/setter vs. Property

• Inhaltlich erreichtmanmit beidenAnsätzen imwesentlichen das gleiche• Properties mögen netter ausschauen, aber ist es das wert?

Vorteil von Properties: Legacy Code!

• Mit Properties können Sie getter/setter-Funktionalität einer Klasse hin-zufügen ohne nutzenden Code zu ändern!

• Das ist mit bloßen getter/setter nicht möglich; Sie müssten alle Pro-gramme ändern, die Ihre Klasse nutzen

• Formal: Wir mussten die Schnittstelle der Klasse nicht ändern und konn-ten trotzdem Funktionalität hinzufügen!

9.7.14 Schnittstelle (Interface)

Allgemeiner: Durch die Nutzung von Properties mussten wir die Schnittstelleder Klasse nicht ändern.

Definition 9.5 (Schnittstelle (Interface)). Die Schnittstelle (das Interface)einer Klasse sind die allgemein zugreifbaren Methoden (samt ihrer Signatu-ren) und Datenattribute der Klasse. Dies beinhaltet die Methoden/Daten evtl.benutzter Oberklassen.

Allgemein zugreifbar heißt hier: vom Zugriff wird nicht durch die Konven-tion _ abgeraten.

Anmerkung: Interfaces in anderen Sprachen

In Sprachen wie Java ist der Begriff des Interfaces von wesentlich größerer Be-deutung als in Python. Dies liegt insbesondere daran, dass Java kein multiple

Page 40: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

40 Liste von Definitionen u.ä.

inheritance beherrscht und versucht, dies über den Interface-Mechanismusnachzubilden. Wir werden dies in folgenden Kapiteln noch genauer untersu-chen.

9.8 Fehlerhafte Nutzung?

9.8.1 Fehler in Methoden?

Fehlerszenario: In Methode tritt Fehler auf

• Die Fehlerbehandlung in den Beispielen oben war sehr seltsam• Rückgabe eines Strings im Fehlerfall?• Keine Rückgabe wenn kein Fehler?

1 def set_temperature(self, value):2 if value < 0:3 return "Error"4 else:5 self._temperature = value

9.8.2 Fehler bei falschen Methoden?

Anderes Fehlerszenario: Eine nicht vorhandene Methode wird aufgerufen

Optionen?

• Ignorieren – denkbar, aber gefährlich– Viel Spaß bei Fählersuche!

• Rückgabewert mit Fehlercode?– Aber wie sollte die Rückgabe aussehen?– Was, wenn der Aufrufer den zurückgegebenen Wert gar nicht aus-wertet?

9.8.3 Fehlermechanismus

Wir brauchen einen leistungsfähigeren Mechanismus, um mit Fehlern umzu-gehen!

Nächstes Kapitel: Exceptions!

Page 41: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.9. Gute Nutzung? Entwurf mit Klassen? 41

9.9 Gute Nutzung? Entwurf mit Klassen?

9.9.1 Was gehört in eine Klasse?

• Bisher: Mechanismen, wie Klassen realisiert, umgesetzt werden• Spannende Frage:

– Wie nutzt man Klassen sinnvoll?– Was ist eine gute Klassenhierarchie?

• Hier: Nur ein paar Anhaltspunkte, Daumenregeln– Siehe z.B. Blog zu Software-Entwurf– Details: VL Software-Entwurf

9.9.2 Prinzip: Single Responsibility

• Eine Klasse sollte genau für einen Aspekt des Gesamtsystems verant-wortlich sein– Genauer: Es sollte nur einen Aspekt geben, dessen Veränderungeine Veränderung der Klasse erfordern könnte

• Wenn nein: Teile die Klasse in Teilklassen auf• Beispiel: Ein Spiel, mit Regeln für Spielzüge und Regeln für Punkte

– Option 1: Eine Klasse, die beides macht– Option 2:

* Eine Klasse für Zustand des Spiels und Züge* Eine Klasse um Punkte zu berechnen

9.9.3 Prinzip: Open-Closed (Meyer, 1988)

• Eine Klasse sollte offen für Erweiterungen sein, aber abgeschlossengegenüber Veränderungen– Grund: Eine Veränderung im Code einer Basisklasse könnte eineKaskade an Änderungen in abgeleiteten Klassen erfordern

• Kernpunkt: Wie wählt man die richtige Abstraktion für Basisklassen?– Was ist Teil der Signatur der Basisklasse?

9.9.4 Prinzip: Abhängigkeiten

• Abstraktionen sollten nicht von Details abhängen

9.9.5 Wie ererbt man?

• Parameter sinnvoll durchreichen– Siehe *args und **kwargs bei Konstruktor

Page 42: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

42 Liste von Definitionen u.ä.

• Sorgfältig überlegen, wo Methoden der Oberklasse aufgerufen werdensollen/müssen

9.9.6 Wie bereitet man Klasse auf Ableitung vor?

• Geeignete Methoden zum Überschreiben vorsehen– Komplexe Methoden in Teilmethoden aufbrechen– Lieber zu viele als zu wenige– Leere Methoden!

1 class C():2 def k(self):3 # does not do anything4 # slot for subclasses to overwrite5 return6

7 def m(self):8 #... do something9 self.k()10 #... do something

9.9.7 Erben oder Besitzen? is-a oder has-a?

• Vererben (is-a): Wiederbenutzung, Adaption von Spezialfällen• Komposition (has-a, Aggregation): Zusammenfügen unterschiedlicherObjekte zu einem neuen Ganzen

• Unterschiedliche Entwurfsaspekte!– Ein Koch ist ein Spezialfall eines Angestellten– Eine Pizzeria hat einen Koch (ein Koch ist keine Pizzeria)

9.10 Zusammenfassung

9.10.1 Zusammenfassung

• Vererbung ist ein Kernmechanismus, um Software-Entwurf mit Klassenund Objekten leistungsfähig zu machen– Wiederbenutzung von Code mit Adaption und Erweiterung– Kapseln von Funktionalität in Basisklassen, schrittweise Speziali-sierung

Page 43: Kapitel 9: Objektorientierung, Vererbunggroups.uni-paderborn.de/fg-karl/lehre/ws1617/gp1/vorlesung/ch9-oo/ch9-oo.pdf · Kapitel 9: Objektorientierung, Vererbung Grundlagen der Programmierung

9.10. Zusammenfassung 43

• Unterklassen können Methoden der Oberklasse überschrieben und da-durch Funktionalität adaptieren oder ergänzen

• Durch Vererbung entstehen Klassenhierarchien mit fortschreitenderSpezialisierung und Adaptierung der Funktionalität

• Konvention für die Nutzen von Attributen (Property)• Reflection als erweiterte Möglichkeit

9.10.2 Spezialisierung und Generalisierung

Abbildung 9.15: Klassen erlauben auch eine Verallgemeinerung