Download
konzepte objektorientierter programmierung n.
Skip this Video
Loading SlideShow in 5 Seconds..
Konzepte objektorientierter Programmierung PowerPoint Presentation
Download Presentation
Konzepte objektorientierter Programmierung

Konzepte objektorientierter Programmierung

110 Views Download Presentation
Download Presentation

Konzepte objektorientierter Programmierung

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. Konzepte objektorientierter Programmierung Klaus Becker 2009

  2. Objektorientierung "Objektorientierung ist die derzeitige Antwort auf die gestiegene Komplexität der Softwareentwicklung." Oestereich: Objektorientierte Software-Entwicklung

  3. Teil 1 Objekte

  4. S Konto-Nr.234126 Freunde des Burggymnasiums Kontoauszug Blatt 342 Datum Erläuterung Betrag 01.07.2009 Miete der Fruchthalle - Sommerkonzert 450.00 - 08.07.2009 Spende eines ehemaligen Schülers 1000.00 + 10.07.2009 Zuschuss zum Whiteboard 800.00 - Kontostand in EUR, 11.07.2009 2130.00 + Verwaltung von Bankkonten Ziel ist es, ein System zur Verwaltung von Bankkonten zu entwickeln. Dieses System soll recht einfach gestaltet werden, um es leicht durchschaubar zu halten. Aus diesem Grund werden wir auf viele Aspekte eines realen Bankkontenverwaltungssystem verzichten.

  5. S Konto-Nr.234126 Freunde des Burggymnasiums Kontoauszug Blatt 342 Datum Erläuterung Betrag 01.07.2009 Miete der Fruchthalle - Sommerkonzert 450.00 - 08.07.2009 Spende eines ehemaligen Schülers 1000.00 + 10.07.2009 Zuschuss zum Whiteboard 800.00 - Kontostand in EUR, 11.07.2009 2130.00 + Verwaltung von Bankkonten Wesentliche zu verwaltende Daten erkennt man auf einem Kontoauszug. Kontonummer Kontoinhaber auszahlen einzahlen auszahlen Kontostand Ein Bankkonto hat eine bestimmte Kontonummer (und einen Kontoinhaber - von dem wir vorerst einmal absehen). Ein Bankkonto hat zudem einen bestimmten Stand - das ist der Geldbetrag, der aktuell auf dem Konto verfügbar ist. Von einem Bankkonto kann man Geldbeträge auszahlen, man kann aber Geldbeträge auf ein Konto einzahlen.

  6. S Konto-Nr.234126 Freunde des Burggymnasiums Kontoauszug Blatt 342 Datum Erläuterung Betrag 01.07.2009 Miete der Fruchthalle - Sommerkonzert 450.00 - 08.07.2009 Spende eines ehemaligen Schülers 1000.00 + 10.07.2009 Zuschuss zum Whiteboard 800.00 - Kontostand in EUR, 11.07.2009 2130.00 + Objektorientierter Modellierungsansatz So wie die zu verwaltende Welt aus Objekten - hier Konten - besteht, so soll das Verwaltungssystem aus Softwareobjekten aufgebaut werden. Softwareobjekt

  7. Softwareobjekt in Aktion Wenn man das Programm konto.py ausführt, dann lässt sich folgender Python-Dialog führen. Probiere das einmal aus. >>> konto = Konto(234126) >>> konto.nr 234126 >>> konto.stand 0 >>> konto.stand = 2380.0 >>> konto.stand 2380.0 >>> konto.auszahlen(450.0) >>> konto.stand 1930.0 >>> konto.einzahlen(1000.0) >>> konto.stand 2930.0 >>> konto.auszahlen(800.0) >>> konto.stand 2130.0

  8. Objekte Ein Objekt ist eine Einheit, die Daten mit Hilfe von Attributen verwalten und Operationen zur Verarbeitung der verwalteten Daten mit Hilfe von Methoden ausführen kann. Attribute sind - an Objekte gebundene - Variablen zur Verwaltung von Daten. Diese entsprechen in der Regel den Eigenschaften der betreffenden Objekte. Methoden sind - an Objekte gebundene - Prozeduren oder Funktionen zur Verarbeitung von Daten. Diese Methoden werden ausgeführt, wenn das betreffende Objekt Operationen ausführt. Ein Objekt befindet sich stets in einem bestimmten Zustand. Der aktuelle Objektzustand wird durch die aktuellen Werte der Attribute festgelegt. Objekt Attribute - Attributwerte Ausführung einer Methode Objektdiagramm

  9. Objekte Zugriff auf Attribute: Objekt objekt.attribut konto.stand = 2380.0 Aktivierung von Methoden: objekt.methode Attribute - Attributwerte konto.einzahlen(1000.0) Ausführung einer Methode

  10. Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.1.4) Lade die Datei wuerfel.txt herunter (benenne sie in wuerfel.py um) und führe einen Python-Dialog analog zum folgenden: >>> w = Wuerfel() >>> w.augen 1 >>> w.werfen() >>> w.augen 6 (a) Was leistet das Attribut augen des Objekts w, was die Methode werfen()? (b) Beschreibe den gezeigten Ablauf mit Hilfe von Objektdiagrammen.

  11. Teil 2 Klassen

  12. Ein Bauplan für Konto-Objekte class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): # ... >>> k1 = Konto(5) >>> k1.nr 5 >>> k1.stand 0 >>> k1.einzahlen(100.0) >>> k1.stand 100.0 Aufgabe 1: Analysiere diese Klassendeklaration und ergänze den fehlenden Teil # .... Überprüfen kannst du deinen Lösungsvorschlag, indem du die Klassendeklaration unter einem geeigneten Namen (z. B. konto.py) abspeicherst und ausführst. Wenn du alles richtig gemacht hast, dann sollte z. B. der oben gezeigte Python-Dialog möglich sein.

  13. Ein Bauplan für Konto-Objekte class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): # ... >>> k1 = Konto(5) >>> k1.einzahlen(1000.0) >>> k2 = Konto(8) >>> ... Aufgabe 2: Versuche auch einmal, mehrere Konto-Objekte zu erzeugen. Überweise mit passenden Methoden 500.0 (Euro) vom Konto mit der Kontonummer 5 auf das Konto mit der Kontonummer 8.

  14. Klassen Eine Klasse ist ein Bauplan für Objekte. Dieser Bauplan legt genau fest, welche Attribute die zu konstruierenden Objekte haben sollen und welche Methoden sie ausführen können sollen. Klassendiagramm Ein Objekt (als Exemplar einer Klasse) ist eine Einheit, die nach dem Bauplan der zugeordneten Klasse erzeugt wurde. Ein Objekt verfügt somit über die Attribute, die in der Klasse festgelegt sind. Diesen Attributen können - im Unterschied zur Klasse - Attributwerte zugewiesen werden. Ein Objekt kann zudem sämtliche Methoden der Klasse ausführen. Ausgenommen bleibt hier nur die Methode, deren Name mit dem Klassennamen übereinstimmt (s. u.). Objekte können mit Namen versehen werden, über die sie dann gezielt angesprochen werden können. Objektdiagramm

  15. Konstruktor / Destruktor Zur Erzeugung von Objekten verfügt eine Klasse über eine spezielle Methode, die sogenannte Konstruktormethode. Zur Vernichtung von Objekten verfügt eine Klasse über eine sogenannte Destruktormethode. Konstruktor Ein Software-Objekt hat - wie viele Objekte der realen Welt - eine bestimmte Lebensdauer. Es muss erzeugt werden, bevor es in Aktion treten kann, und kann auch wieder vernichtet werden. In einem Klassendiagramm wird eine Konstruktormethode dadurch gekennzeichnet, dass sie denselben Namen wie die Klasse selbst trägt. Oft wird diese spezielle Methode in Klassendiagrammen aber auch weggelassen. Beachte, dass eine Konstruktormethoden keine Methode ist, die ein Objekt ausführen kann. Destruktormethoden werden in der Regel in Klassendiagrammen weggelassen.

  16. Klassendeklaration in Python Klassenname Oberklasse Schlüsselwort Doppelpunkt class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag Einrückung Konstruktor Attribute Attribute Methode Methode Referenz auf Objekt

  17. Objekterzeugung in Python class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag Klassendeklaration >>> k1 = Konto(5) >>> k2 = Konto(8) >>> k1.nr 5 >>> k1.stand 0 >>> k2.nr 8 >>> k2.stand 0 >>> k1.__dict__ {'nr': 5, 'stand': 0} >>> k2.__dict__ {'nr': 8, 'stand': 0} >>> k = Konto(5) >>> k.stand 0.0 >>> del k >>> k.stand Traceback (most recent call last): File ... NameError: name 'k' is not defined >>> Erzeugung eines Objekts Vernichtung eines Objekts Inspektion eines Objekts

  18. Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.2.5) Gegeben ist eine Implementierung der Klasse Wuerfel(): from random import randint class Wuerfel(object): def __init__(self): self.augen = 1 def werfen(self): self.augen = randint(1, 6) Erzeuge drei Objekte der Klasse Wuerfel und würfele hiermit solange, bis mindestens einer der Würfel eine 6 liefert.

  19. Übungen Aufgabe 2 (siehe www.inf-schule.de 1.12.2.5) Gegeben ist das folgende Klassendiagramm zur Klasse Bruch: Was soll mit einem Objekt der Klasse Bruch beschrieben werden? Entwickle eine geeignete Implementierung und teste sie mit einem Python-Dialog.

  20. Übungen Aufgabe 3 (siehe www.inf-schule.de 1.12.2.5) Wenn man modulo einer vorgegebenen Zahl (man nennt sie auch Modul) zählt, dann bildet man jeweils den Rest bei der Division durch die vorgegebene Zahl. Betrachte als Beispiel die vorgegebene Zahl (Modul) 5. Wenn man modulo 5 zählt, dann geht das so: 0 modulo 5, 1 modulo 5, 2 modulo 5, 3 modulo 5, 4 modulo 5, 5 modulo 5, 6 modulo 5, ... Berechnet man jeweils die Reste, dann ergibt das folgende die Zahlenfolge 0, 1, 2, 3, 4, 0, 1, ... . Wenn man modulo einer vorgegebenen Zahl n zählt, dann ergibt das also die Zahlenfolge 0, 1, ..., (n-1), 0, 1, .... Konzipiere eine Klasse ModuloZaehler (mit einem Klassendiagramm), die Python-Dialoge wie den folgenden ermöglicht. Implementiere die Klasse und teste sie mit geeigneten Python-Dialogen. >>> z = ModuloZaehler(3) >>> z.modul 3 >>> z.stand 0 >>> z.weiterzaehlen() >>> z.stand 1 >>> z.weiterzaehlen() >>> z.stand 2 >>> z.weiterzaehlen() >>> z.stand 0 >>> z.zurueckzaehlen() >>> z.stand 2 >>> z.nullsetzen() >>> z.stand 0

  21. Übungen Aufgabe 5 (siehe www.inf-schule.de 1.12.2.5) Die Klasse Schlange kann man verwenden, um Warteschlangen zu simulieren. Erläutere, was die Methoden der Klasse Schlange bewirken. Verdeutliche deine Erläuterungen jeweils mit einem geeigneten Python-Protokoll. class Schlange(object): def __init__(self): self.liste = [] def istLeer(self): if self.liste == []: return True else: return False def mitLetztem(self, element): self.liste = self.liste + [element] def ohneErstes(self): if not self.istLeer(): self.liste = self.liste[1:] ... ... def anzahlElemente(self): return len(self.liste) def getSchlange(self): return self.liste def setSchlange(self, liste): self.liste = liste

  22. Übungen Aufgabe 6 (siehe www.inf-schule.de 1.12.2.5) Die folgende Deklaration des Konstruktors erlaubt es, Objekte flexibel mit Anfangswerten zu versehen: >>> k1 = Konto() >>> k1.nr 0 >>> k1.stand 0 >>> k2 = Konto(1) >>> k2.nr 1 >>> k2.stand 0 >>> k3 = Konto(2, 1000.0) >>> k3.nr 2 >>> k3.stand 1000.0 >>> k4 = Konto(betrag=400.0) >>> k4.nr 0 >>> k4.stand 400.0 class Konto(object): def __init__(self, nummer=0, betrag=0): self.nr = nummer self.stand = betrag def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag Erkläre, wie die jeweiligen Attributwerte der Objekte zustande kommen.

  23. Teil 3 Verwaltung von Objekten

  24. Objekte und ihre Identität >>> k1 = Konto(3) >>> k1 <__main__.Konto object at 0x0135D670> >>> id(k1) 20305520 >>> hex(20305520) '0x135d670' >>> k2 = Konto(4) >>> id(k2) 20307184 Aufgabe: Was verbirgt sich wohl hinter der Identitätsnummer eines Objekts? Prüfe mit geeigneten Python-Dialogen, ob sich die Identitätsnummer eines Objekts ändert, wenn sich der Zustand eines Objekts beim Ausführen einer Methode ändert. Python-Dialog

  25. Konto kopieren? >>> k1 = Konto(6) >>> k2 = k1 >>> k1.stand ??? >>> k2.stand ??? >>> k2.einzahlen(100.0) >>> k1.stand ??? >>> k2.stand ??? >>> k2 = Konto(7) >>> k1.stand ??? >>> k2.stand ??? >>> Aufgabe: Stell Vermutungen auf, was anstelle der drei Fragezeichen jeweils steht. Teste, ob deine Vermutungen stimmen. Kannst du dir die Ergebnisse erklären? Benutze auch den id-Operator, um Einsicht über die verwalteten Objekte zu erhalten. Python-Dialog

  26. Identität von Objekten (Daten-) Objekte haben - analog zu Objekten unserer Lebenswelt - ebenfalls eine Identität. Zur eindeutigen Identifizierung werden sie mit Identitätsnummern versehen. Verschiedene Objekte unterscheiden sich in ihrer Identitätsnummer. Sie können aber durchaus denselben Objektzustand haben. Ein Objekt behält während seiner Lebensdauer immer die einmal vergebene Identitätsnummer. Auch wenn sich der Zustand des Objekts verändert, so bleibt doch die Identitätsnummer des Objekts bestehen. Häufig verwendet hierzu man eine Adresse im Speicher des Rechners als Identitätsnummer. Die Identitätsnummer eines Objekts zeigt dann auf den Speicherbereich, in dem die Daten des Objekts abgelegt sind. Diese Identifikation von Objekten durch eine Lokalisierung im Speicher setzt natürlich voraus, dass Objekte im Speicher nicht hin und her wandern, sondern dass der einmal zugeteilte Speicherbereich während der Lebensdauer eines Objekts bestehen bleibt. Wir gehen im Folgenden von dieser Vorstellung aus.

  27. Zeiger / Referenzen Eine Variable ist ein Name, der (in der Regel) mit einem Objekt verknüpft ist. Wenn eine Variable ein (Daten-) Objekt verwaltet, dann verwaltet es die Speicheradresse (bzw. Identitäsnummer) dieses Objekts. Da die Speicheradresse auf das Objekt zeigt bzw. das Objekt referenziert, nennt man eine solche Adresse auch Zeiger bzw. Referenz und die Variable zur Verwaltung der Adresse Zeigervariable bzw. Referenzvariable.

  28. Zuweisungen bei Zeigervariablen k1 = Konto(6) k2 = k1 k2.einzahlen(100.0) k2 = Konto(7)

  29. Objekte in Python Veränderbares Objekt Unveränder-bares Objekt from konto import * def null(konto): print(id(konto)) konto.stand = 0.0 print(id(konto)) k = Konto(9) k.einzahlen(100.0) print(k.stand) print(id(k)) null(k) print(k.stand) print(id(k)) def null(zahl): print(id(zahl)) zahl = 0.0 print(id(zahl)) z = 100.0 print(z) print(id(z)) null(z) print(z) print(id(z)) kein Seiteneffekt Seiteneffekt Python unterscheidet zwischen veränder-baren und unveränderbaren Objekten.

  30. Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.3.5) Wenn man den Objektbezeichner vom Python-Interpreter auswerten lässt, dann wird der vom Bezeichner verwaltete Wert angezeigt. Warum zeigt der Python-Dialog, dass hier Zeiger verwaltet werden? class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag >>> k1 = Konto(6) >>> k2 = k1 >>> k1 <__main__.Konto object at 0x01DA7F10> >>> k2 <__main__.Konto object at 0x01DA7F10> >>> k2 = Konto(8) >>> k2 <__main__.Konto object at 0x01DB5CB0>

  31. Übungen Aufgabe 2 (siehe www.inf-schule.de 1.12.3.5) Jedes Objekt wird zur Identifierung mit einer eindeutigen Identitätsnummer versehen. Mit Hilfe des id-Operators lässt sich diese Identitätsnummer in Python ermitteln. Was zeigt der abgebildete Python-Dialog? class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag >>> k1 = Konto(6) >>> k2 = k1 >>> id(k1) 31153488 >>> id(k2) 31153488 >>> k2 = Konto(8) >>> id(k2) 31096624

  32. Übungen Aufgabe 3 (siehe www.inf-schule.de 1.12.3.5) Die Funktion mitNeuemErsten soll dazu dienen, in einer Liste das erste Element auszutauschen. Vegleiche die beiden folgenden Implementierungen und erkläre das unterschiedliche Verhalten. def mitNeuemErsten(liste, element): liste[0] = element return liste L = [1, 2, 3] M = mitNeuemErsten(L, 0) print(L) print(M) def mitNeuemErsten(liste, element): hilf = [element] + liste[1:] return hilf L = [1, 2, 3] M = mitNeuemErsten(L, 0) print(L) print(M)

  33. Teil 4 Modularisierung und Datenkapselung

  34. Konto überziehen Ein Konto soll höchstens um 1000 Euro überzogen werden dürfen. class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 self.minimum = -1000.0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): if self.stand - betrag >= self.minimum: self.stand = self.stand - betrag else: print("Auszahlung nicht möglich!") >>> k = Konto(9) >>> k.stand = 600.0 >>> k.stand 600.0 >>> auszahlungsbetrag = 2750.0 >>> k.stand = k.stand - auszahlungsbetrag >>> k.stand -2150.0 Nutzung der Klasse Implementierung der Klasse Aufgabe 1: Warum ist dieser Dialog nicht im Sinne des Bankkontenverwaltungssystems?

  35. Konto überziehen Die Entwickler der Klasse Konto veröffentlichen folgende Schnittstelle dieser Klasse: from konto import Konto k = Konto(9) # Testlauf k.einzahlen(600.0) print(k.getStand()) auszahlungsbetrag = 2750.0 k.auszahlen(auszahlungsbetrag) print(k.getStand()) Schnittstelle zur Klasse Nutzung der Klasse Aufgabe 2: Warum macht es hier Sinn, die Attribute der Klasse Konto nicht zu veröffentlichen und eine Veränderung von Attributwerten nur über veröffentlichte Merhoden zu erlauben? Aufgabe 3: Im Testprogramm wird die Methode getStand benutzt, die in der Schnittstelle vorgesehen ist. Was soll diese Methode leisten? Ergänze die oben gezeigte Implementierung der Klasse Konto um die noch fehlenden Methoden und führe das Testprogramm aus.

  36. Modularisierung Modularisierung ist ein Prinzip, nach dem viele Systeme entwickelt werden. Die Idee besteht darin, das Gesamtsystem nach dem Baukastenprinzip aus Einzelbausteinen (den sogenannten Modulen) zusammenzusetzen. "Unsere Partyzelte können in verschiedenen Größen aufgebaut werden. Da die Partyzelte und Festzelte aus Modulen bestehen, ist es sehr einfach, sie zu erweitern. Die Abbildung zeigt ein mögliches Kombinationsbeispiel der Module." Ein Softwaremodul ist eine in sich abgeschlossene Einheit, die man vielfältig bei Problem-lösungen einsetzen kann. Es reicht dabei zu wissen, welche Operationen die Einheit dem Benutzer zur Verfügung stellt. Wie die Operationen programmiert sind, muss man dagegen nicht wissen. Grundidee der objektorientierten Modularisierung ist es, Softwaremodule als Klassen zu konzipieren .

  37. Modularisierung in Python from konto import Konto k = Konto(9) # Testlauf k.einzahlen(600.0) print(k.getStand()) auszahlungsbetrag = 2750.0 k.auszahlen(auszahlungsbetrag) print(k.getStand()) from konto import * k = Konto(9) # Testlauf k.einzahlen(600.0) print(k.getStand()) auszahlungsbetrag = 2750.0 k.auszahlen(auszahlungsbetrag) print(k.getStand()) import konto k = konto.Konto(9) # Testlauf k.einzahlen(600.0) print(k.getStand()) auszahlungsbetrag = 2750.0 k.auszahlen(auszahlungsbetrag) print(k.getStand()) Der Name "Konto" wird in den aktuellen Namensraum übernommen.

  38. Geheimnisprinzip / Datenkapselung Beim Autobau wird somit - zumindest in bestimmten Bereichen - das Geheimnisprinzip angewandt. Bestimmte Eigenschaften des Motors können nur über speziell hierfür vorgesehene Schnittstellen ermittelt werden. So kann der aktuelle Ölstand nur an einem hierfür vorgesehenen Messstab abgelesen werden. Änderungen am aktuellen Motorzustand können direkt ebenfalls nur an bestimmten hierfür vorgesehenen Stellen vorgenommen werden. Motoröl lässt sich nur in die hierfür vorgesehene Öffnung einfüllen. Alles weitere über das Innere des Motors bleibt für den normalen Autofahrer unzugänglich und in diesem Sinne geheim. Bei der objektorientierten Software-Entwicklung geht man völlig analog vor. Nach dem Geheimnisprinzip werden die internen Daten eines Objekts (die in der Regel über Attribute verwaltet werden) so verborgen, dass ein direkter Zugriff hierauf nicht möglich ist. Jeder Zugriff auf interne Daten und jede Veränderung von internen Daten darf nur über spezielle, hierfür vorgesehene Methoden erfolgen. Man nennt diese Vorgehensweise auch Datenkapselung.

  39. Zugriffsrechte / Zugriffsmethoden Um interne Daten kapseln zu können, werden Zugriffrechte festgelegt. Der Entwickler einer Klasse hat die Möglichkeit, Attribute und Methoden einer Klasse als öffentlich oder privat zu deklarieren. Lesende und schreibende Zugriffe auf Attribute bzw. Methoden eines Objekts sind nur möglich, wenn diese öffentlich sind. Private Attribute bzw. Methoden können dagegen nur bei der Implementierung der betreffenden Klasse benutzt werden. Im Klassendiagramm werden die Zugriffsrechte auf die Attribute und Methoden mit Hilfe der Symbole + (für öffentlich) und - (für privat) festgelegt. Verfolgt man die Strategie, alle Attribute als privat zu deklarieren, so besteht keine Möglichkeit, direkt schreibend oder lesend auf Attributwerte zuzugreifen. Um dennoch solche Zugriffe zu erlauben, werden spezielle öffentliche Zugriffsmethoden bereitgestellt. Das Klassendiagramm wird daher um solche Zugriffsmethoden erweitert.

  40. Zugriffsrechte in Python class Konto(object): def __init__(self, nummer): self.__nr = nummer self.__stand = 0 self.__minimum = -1000.0 def einzahlen(self, betrag): self.__stand = self.__stand + betrag def auszahlen(self, betrag): if self.__stand - betrag >= self.__minimum: self.__stand = self.__stand - betrag else: print("Auszahlung nicht möglich!") def getStand(self): return self.__stand def setStand(self, stand): if stand >= self.__minimum: self.__stand = stand else: print("Initialisierung nicht möglich!") # ... Ein Attribut / eine Methode wird in Python zu einem privaten Attribut, wenn der Attributname mit zwei Unterstrichen beginnt und nicht mit Unterstrichen endet. Beginnt der Attributname / Methodenname nicht mit einem Unterstrich, so ist das Attribut öffentlich.

  41. Datenkapselung in Python >>> k = Konto(3) >>> k.__stand Traceback (most recent call last): File ... AttributeError: 'Konto' object has no attribute '__stand' >>> k.__dict__ {'_Konto__minimum': -1000.0, '_Konto__nr': 3, '_Konto__stand': 0} >>> k._Konto__stand 0 Wie erwartet kann man auf das private Attribut __stand des neu erzeugten Objekts k nicht zugreifen. Python meldet als Fehler, dass es kein Attribut __stand gibt. Der Aufruf k.__dict__ verrät, woran das liegt. Ein Aufruf wie k.__dict__ listet sämtliche Attribute mit den zugehörigen Attributwerten des betreffenden Objekts auf. Interessant ist hier, dass sich das private Attribut __stand hinter einem anderen Namen versteckt. Wenn man weiß, wie der neue Name - hier _Konto__stand - gebildet wird, dann kann man durchaus auf das betreffende Attribut zugreifen. Also: Private Attribute werden in Python mit anderen Namen versehen, so dass kein direkter Zugriff möglich ist. Kennt man den Namen, hinter dem sich ein privates Attribut verbirgt, so kann man durchaus auf dieses Attribut zugreifen. Python liefert also keinen echten Zugriffsschutz.

  42. Datenkapselung in Python >>> k = Konto(3) >>> k.__stand Traceback (most recent call last): File ... AttributeError: 'Konto' object has no attribute '__stand' >>> k.__dict__ {_Konto__minimum': -1000.0, '_Konto__nr': 3, '_Konto__stand': 0} >>> k.__stand = 100.0 >>> k.__stand 100.0 >>> k.__dict__ {_Konto__minimum': -1000.0, '_Konto__nr': 3, '_Konto__stand': 0, '__stand': 100.0} Ein erster Zugriff auf das private Attribut __stand scheitert. Dann aber ist es - entgegen aller Zugriffslogik - scheinbar möglich, dem privaten Attribut __stand einen Wert zuzuweisen. Der Aufruf k.__dict__ erklärt erst, was hier passiert ist. Neben dem privaten Attribut __stand, das sich hinter dem neuen Namen _Konto__stand versteckt, gibt es noch öffentliches Attribut __stand, auf das man direkt zugreifen kann. Wir werden im Folgenden bei der Implementierung von Klassen in Python keine Attribute als private Attribute deklarieren. In der Regel werden wir auch keine Zugriffsmethoden einführen und nutzen. Nur in begründeten Ausnahmefällen werden wir von dieser Vereinbarung abweichen.

  43. Schnittstellen Die Schnittstelle einer Klasse liefert alle Informationen, die man benötigt, um die Klasse benutzen zu können. Hierzu gehört eine genaue Beschreibung aller öffentlichen Attribute und Methoden der Klasse. Für jedes Attribut benötigt man den erwarteten Datentyp, für jede Methode die Signatur (d. h. die genaue Festlegung der Parametertypen und bei Funktionen des Rückgabetyps) und eine Verhaltensbeschreibung. Konto(nummer: int) nachher: Ein Objekt der Klasse Konto ist erzeugt. Der Wert des Attributs nr entspricht dem übergebenen Wert des Parameters nummer, der Wert des Attributs stand beträgt 0, der Wert des Attributs minimum beträgt -1000.0. auszahlen(betrag: float) vorher: Das Konto-Objekt hat einen beliebigen Zustand. nachher: Der Wert des Attributs stand des Konto-Objekts ist um den übergebenen Wert des Parameters betrag reduziert.

  44. Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.4.8) Zur Klasse Wuerfel soll folgende Implementierung in einer Datei wuerfel.py abgespeichert sein: from random import randint class Wuerfel(object): def __init__(self): self.augen = 1 def werfen(self): self.augen = randint(1, 6) (a) Was leistet das folgende Programm, das das Modul Wuerfel als Baustein benutzt? (b) Es soll getestet werden, wie oft man drei Würfel werfen muss, bis mindestens einer eine 6 liefert. Entwickle ein geeignetes Simulationsprogramm, das die Klasse Wuerfel als Baustein benutzt. from wuerfel import * # Würfelprogramm w = Wuerfel() w.werfen() versuche = 1 while w.augen != 6: w.werfen() versuche = versuche + 1 print("Versuche:", versuche)

  45. Übungen >>> k = Konto(100) >>> s = Spielzahl() >>> wA = Wuerfel() >>> wB = Wuerfel() >>> wC = Wuerfel() >>> k.abheben(1) >>> k.stand 99 >>> s.setzen(3) >>> s.zahl 3 >>> wA.werfen() >>> wB.werfen() >>> wC.werfen() >>> wA.augen 3 >>> wB.augen 6 >>> wC.augen 2 >>> k.einzahlen(2) >>> k.stand 101 Aufgabe 2 (siehe www.inf-schule.de 1.12.4.8) Folgende Klassen sollen als Bausteine zur Simulation des Spiels "chuck a luck" zur Verfügung gestellt werden: (a) Implementiere diese Klassen. Mit Hilfe dieser Bausteine sollen dann Python-Dialoge wie der folgende möglich sein. (b) Mit Hilfe eines Simulationsprogramms soll ermittelt werden, ob das chuck-a-luck-Spiel fair ist.

  46. Übungen ... def vollstaendigKuerzen(self): # ggT von Zähler und Nenner best. x = self.zaehler y = self.nenner while y > 0: h = x % y x = y y = h ggt = x # kürzen self.kuerzen(ggt) def add(self, b): x1 = self.zaehler x2 = self.nenner y1 = b.zaehler y2 = b.nenner z1 = x1*y2 + x2*y1 z2 = x2*y2 self.zaehler = z1 self.nenner = z2 self.vollstaendigKuerzen() Aufgabe 3 (siehe www.inf-schule.de 1.12.4.8) (a) Erstell ein Klassendiagramm und eine Schnittstellenbeschreibung zur Klasse Bruch. (b) Entwickle ein Testprogramm, das die Klasse Bruch als Modul benutzt. class Bruch(object): def __init__(self, z, n): self.zaehler = z self.nenner = n def erweitern(self, k): self.zaehler = self.zaehler * k self.nenner = self.nenner * k def kuerzen(self, k): if (self.zaehler % k == 0) and \ (self.nenner % k == 0): self.zaehler = self.zaehler // k self.nenner = self.nenner // k ... (c) Füge der Klasse Bruch weitere Operationen hinzu und teste diese Erweiterung.

  47. Übungen Aufgabe 5 (siehe www.inf-schule.de 1.12.4.8) Teste die Einbindung folgender Modulimporte und ihre Auswirkung auf den globalen Namensraum. Warum wird bei sehr umfangreichen Modulen empfohlen, die erste oder dritte der oben aufgelisteten Einbindungsvarianten zu benutzen? >>> from random import randint >>> globals() >>> from random import * >>> globals() >>> import random >>> globals()

  48. Übungen Aufgabe 6 (siehe www.inf-schule.de 1.12.4.8) (a) Teste diese Implementierung der Klasse Bruch. Irgend etwas stimmt hier nicht. Findest du den Fehler? Benutze die Operation __dict__() zur Fehlersuche. Erkläre, was hier schiefläuft. (b) Warum ist es so schwierig, Flüchtigkeitsfehler wie den oben gezeigten zu finden? class Bruch(object): def __init__(self, z, n): self.zaehler = z self.nenner = n def erweitern(self, k): self.zahler = self.zaehler * k self.nenner = self.nenner * k def kuerzen(self, k): if (self.zaehler % k == 0) and \ (self.nenner % k == 0): self.zaehler = self.zaehler // k self.nenner = self.nenner // k

  49. Teil 5 Beziehungen

  50. S Konto-Nr.5 Adriana Müller Kontoauszug Blatt 3 Datum Erläuterung Betrag 01.07.2009 Handykosten 45.00 - 08.07.2009 Zuschuss von Oma und Opa 100.00 + 10.07.2009 Schuhe 80.00 - Kontostand in EUR, 11.07.2009 50.00 + Verwaltung des Kontoinhabers Der Kontoinhaber soll jetzt ebenfalls mitverwaltet werden. Hierzu muss das Objektmodell erweitert werden. Mehrere Vorschläge stehen zur Diskussion Aufgabe: Vergleiche die folgenden Vorschläge. Vorschlag 2: Vorschlag 1: