===== Aufgabe zur Objektorientierung in Python ===== ==== Aufgabe 1 ==== Erstelle eine Klasse "Bankkonten". Überlege dir sinnvolle Attribute und Methoden, die man für ein Bankkonto braucht. Das dauert. Wirklich. Man muss sich in den Schmonz ziemlich reindenken und viel probieren! Das Ziel für heute: Du kannst Geldbeträge zwischen unterschiedlichen Konten verschieben (dort abbuchen, da aufbuchen). Das lässt sich mit dem Wissen, was du hast, elegant und weniger elegant lösen. Die harte Variante: Du kannst einer Methode eines Objekts auch ein anderes Objekt übergeben (das ist aber schon die ganz harte Variante für den Anfang, an dem du stehst). ++++ Klicke hier für einen Lösungsansatz | # Thx an Aaron für große Teile des Codes! class konto: # Konstruktor, der uns das neue Konto baut def __init__(self, nummer, kontostand): self.nummer = nummer self.kontostand = kontostand # Methode zum Überweisen # Erwartet: value (Summe, die übertragen werden soll) # Erwartet: target (Zielkonto) # Auf den eigenen Kontostand können wir mit self.kontostand zugreifen # Auf den Zielkontostand können wir mit target.kontostand zugreifen # target haben wir im Hauptprogramm übergeben def ueberweisen(self, value, target): self.kontostand = self.kontostand - value target.kontostand = target.kontostand + value konto1 = konto(1, 1000) konto2 = konto(2, 2000) print("Alter Kontostand:", konto1.kontostand) print("Alter Kontostand:", konto2.kontostand) # Wir greifen auf die Methode "überweisen" innerhalb der Klasse konto zu. # Vor dem Punkt steht das Objekt, das wir verändern wollen konto1.ueberweisen(100, konto2) print("Neuer Kontostand:", konto1.kontostand) print("Neuer Kontostand:", konto2.kontostand) ++++ ==== Aufgabe 2 ==== Bankkonten sind eine komplexe Sache. Erwachsene dürfen z.B. im Rahmen eines Dispositionskredits ihr Konto um einen bestimmten Betrag "überziehen". Spezielle Jugendkonten bieten den kompletten Funktionsumfang, verbieten aber jedwede Überziehung. Überlege dir, wie du Dispositionskredite und Jugendkonten in deiner Kontoklasse realisieren kannst. Die Dispositionskredite sollen sich durch eine Methode frei wählen lassen, jedoch nie über 50% des aktuellen Kontostandes, d.h. das Konto muss beim Einrichten im Plus sein. Wenn ein Jugendlicher jedoch versucht, sich einen solchen Kredit einzuräumen, soll diese Aktion scheitern. Jugendliche sollen ihr Konto zudem nicht überziehen können. ++++ Klicke hier für einen Lösungsansatz | class konto: # Konstruktor, der uns das neue Konto baut def __init__(self, nummer, kontostand, isAdult, dispo): self.nummer = nummer self.kontostand = kontostand self.isAdult = isAdult self.dispo = dispo def ueberweisen(self, value, target): self.kontostand = self.kontostand - value target.kontostand = target.konto def setDispo(self,value): if self.isAdult == 0: print("Du bist zu jung!") return if value > self.kontostand/2: print("Zu wenig Guthaben!") return else: self.dispo = value print("Dispo eingerichtet!") # kundenkonto[0] hat die Nummer 1 und 1000 Euro Guthaben # kundenkonto[1] hat die Nummer 2 und 2000 Euro Guthaben kundenkonten = [konto(1,1000,0,0), konto(2,2000,1,0)] # Geht schief, weil Jugendkonto kundenkonten[0].setDispo(500) # Geht schief, weil Deckung nicht ausreicht kundenkonten[1].setDispo(2000) # klappt kundenkonten[1].setDispo(500) ++++ ==== Aufgabe 3 ==== Auch die Bank braucht hin und wieder Informationen über ihre Kunden. So sollen Mitarbeitende z.B. einfach herausfinden können, wie viele Jugendkonten und Erwachsenenkonten es gerade gibt. Das kannst du z.B. alles über eine Methode im Hauptprogramm realisieren. Wenn du das elegant mit einer Schleife machen möchtest, musst du ja durch alle Konten laufen. Um die Konten in einer Schleife durchzählen zu können, wäre es ja hübsch, sie über einen Index ansprechen zu können, z.B. **kundenkonto[0].getDispo()** oder **kundenkonto[0].isAdult**. Du kannst dir dazu ein Array von Objekten anlegen. Die Elemente sind durch ein Komma getrennt. In runden Klammern stehen hinter jedem Element die Basiswerte. Das wirst du ggf. an deine Klasse anpassen müssen. Die Umsetzung ist recht einfach: class konto: # Konstruktor, der uns das neue Konto baut def __init__(self, nummer, kontostand): self.nummer = nummer self.kontostand = kontostand # kundenkonto[0] hat die Nummer 1 und 1000 Euro Guthaben # kundenkonto[1] hat die Nummer 2 und 2000 Euro Guthaben kundenkonten = [konto(1,1000), konto(2,2000)] print(kundenkonto[1].kontostand) === Zur Erinnerung === **len(array)** gibt die die Anzahl der Elemente in einem Array zurück. ++++ Klicke hier für einen Lösungsansatz | class konto: # Konstruktor, der uns das neue Konto baut def __init__(self, nummer, kontostand, isAdult, dispo): self.nummer = nummer self.kontostand = kontostand self.isAdult = isAdult self.dispo = dispo def ueberweisen(self, value, target): self.kontostand = self.kontostand - value target.kontostand = target.konto def setDispo(self,value): if self.isAdult == 0: print("Du bist zu jung!") return if value > self.kontostand/2: print("Zu wenig Guthaben!") return else: self.dispo = value print("Dispo eingerichtet!") # kundenkonto[0] hat die Nummer 1 und 1000 Euro Guthaben # kundenkonto[1] hat die Nummer 2 und 2000 Euro Guthaben kundenkonten = [konto(1,1000,0,0), konto(2,2000,1,0)] # Zählvariablen youth_count = 0 adult_count = 0 for i in range(0,len(kundenkonten)): if (kundenkonten[i].isAdult == 1): adult_count += 1 else: youth_count += 1 print(f'Es gibt {youth_count} Jugendkonten und {adult_count} Erwachsenenkonten.') ++++ ==== Aufgabe 4 ==== Der Bankvorstand hat sich gemeldet. Die Summe aller positiven Kontostände soll angezeigt werden können sowie die Höhe aller gerade laufenden Dispositionskredite. Außerdem soll berechnet werden können, ob die Bank selbst im Plus oder im Minus ist. ++++ Klicke hier für einen Lösungsansatz | class konto: # Konstruktor, der uns das neue Konto baut def __init__(self, nummer, kontostand, isAdult, dispo): self.nummer = nummer self.kontostand = kontostand self.isAdult = isAdult self.dispo = dispo def ueberweisen(self, value, target): self.kontostand = self.kontostand - value target.kontostand = target.konto def setDispo(self,value): if self.isAdult == 0: print("Du bist zu jung!") return if value > self.kontostand/2: print("Zu wenig Guthaben!") return else: self.dispo = value print("Dispo eingerichtet!") # kundenkonto[0] hat die Nummer 1 und 1000 Euro Guthaben # kundenkonto[1] hat die Nummer 2 und 2000 Euro Guthaben kundenkonten = [konto(1,1000,0,0), konto(2,2000,1,1000)] # Variablen zum Aufsummieren sum_credit = 0 sum_dispo = 0 for i in range(0,len(kundenkonten)): sum_credit += kundenkonten[i].kontostand sum_dispo += kundenkonten[i].dispo print(f'Die Guthabenhöhe aller Konten beträgt {sum_credit} Euro und die Höhe der Dispokredite beträgt {sum_dispo} Euro. Der Guthabenstand der Bank beträgt insgesamt {sum_credit} Euro.') ++++ ==== Aufgabe 5 ==== Bei jeder Überweisung soll nun eine Gebühr von 1,5% des Überweisungsbetrages erhoben werden - außer bei Jugendkonten. ++++ Klicke hier für einen Lösungsansatz | Bei Erwachsenenkonten ziehen wir bei jeder Überweisung 101,5% vom Konto ab, bei Jugendkonten nicht. Problem: Momentan verschwindet die Gebühr einfach im Nirgendwo. Hast du Ideen? def ueberweisen(self, value, target): if (self.isAdult == 1): self.kontostand = self.kontostand - value * 1.015 else: self.kontostand = self.kontostand target.kontostand = target.konto ++++ ==== Aufgabe 6 ==== Es gibt ein ernstes Problem mit der Methode zur Überweisung. Wenn der Kunde negative Überweisungsbeträge eingibt, bekommt er Geld **vom** anderen Konto. Das soll unterbunden werden. ++++ Klicke hier für einen Lösungsansatz | def ueberweisen(self, value, target): if (value < 0): print("Nicht autorisierte Anforderung!") return if (self.isAdult == 1): self.kontostand = self.kontostand - value * 1.015 else: self.kontostand = self.kontostand - value target.kontostand = target.konto + value ++++ ==== Aufgabe 7 ==== Die Schulbücherei braucht deine Hilfe. Sie möchte weg von den ganzen Zettelkästen im Verleih. Die Schüler:innen sollen Bücher nach Kriterien suchen können. Sie dürfen zudem bis zu drei Bücher ausleihen, wenn diese Bücher nicht schon verliehen sind. Überlege dir eine geeignete Klasse "Buch" und eine geeignete Klasse "Schüler". Welche Attribute und Methoden brauchen diese Klassen mindestens? Teste deine Klassen mit Beispielsuchen und Beispielausleihvorgängen. * Du erledigst diese Aufgabe mit einem Partner / einer Partnerin. * Die ausgeliehenen Bücher sollen innerhalb einer Person gespeichert werden. Wenn eine Person ausgewählt wird, sollen die von ihr entliehenen Bücher angezeigt werden. * Verzettelt euch nicht! Realisiert nur die Attribute und Methoden, die ihr unbedingt braucht, um Basisfunktionen bereitzustellen * Überlegt bitte einmal, wie ihr Aufgaben im Team verteilen könnt: Es müssen zwei Klassen geschrieben werden, es müssen Objekte zum Testen erzeugt werden, Methoden müssen getestet werden etc.. === Hinweise === Da nur drei Bücher entliehen werden sollen, kann man es sich einfach machen und einfach drei Attribute für Bücher in der Klasse "Person" hinterlegen. Jedes Atrribut zeigt dann auf ein Buchobjekt - oder eben nicht, wenn keins entliehen ist. Schicker ist es, die Buchobjekte in einem Array von Objekten zu speichern. Damit ist man später flexibler bei der Anzahl der entleihbaren Bücher und braucht auch im Prinzip weniger Speicherplatz. Ein Element anhängen: array = [0,1,2,3] array.append(4) for x in array: print (x) Mehrere Elemente anhängen: array = [0,1,2,3] array.extend([4,5,6,7]) for x in array: print (x) Ein Element löschen: array = [0,1,2,3] array.remove(2) for x in array: print (x) Denke daran, dass du bei einem Array von Objekten nicht mit Werten herumschiebst, sondern mit Objekten, z.B. person[0], book[8]. # Wir nehmen an, dass die Klasse für Personen "person" heißt und N Attribute hat array = [person(Attribut1, Attribut2,...,AttributN), person(Attribut1, Attribut2,...,AttributN), person(Attribut1, Attribut2,...,AttributN), ... ] # Entfernt person[0] aus dem Array array.remove(person[0]) ++++ Klicke hier für einen Lösungsansatz | class book: def __init__(self, id, title, author, isAvailable): self.id = id self.title = title self.author = author self.isAvailable = isAvailable def rent(): self.isAvailable = False def release(): self.isAvailable = True class user: def __init__(self, id, name, surename, hasBooks): self.id = id self.name = name self.surename = surename self.hasBooks = hasBooks # Some Testing book_test = book(1, "Harry Potter - Stein der Weisen", "Joanne K. Rowling", False) print(book_test.title) user_testHasBooks = [] user_test = user(1, "Maik", "Riecken", user_testHasBooks) print(user_test.surename) ++++ ==== Aufgabe 8 ==== Solarmodule sind in aller Munde. Diese bestehen aus einzelnen Solarzellen. Diese haben einen Spannung von ca. 0,6 Volt. Damit eine Solarzelle also 6V liefert, müssen 10 Solarzellen zu einem Modul zusammengeschaltet werden. Wir nehmen vereinfachend an, dass eine einzelne Solarzelle immer 1A an Strom liefert. Damit liefert eine einzelne Zelle P = U * I = 0,6V * 1A = 0,6 Watt. Ein Solarmodul hat immer eine Seriennummer. - Schreibe eine Klasse "solarmodule" und eine Klasse "solarcell". Überlege dir, welche Attribute und Methoden beide Klassen mindestens brauchen. - Man soll nur Solarmodule mit 120, 210 und 390 Watt erzeugen und an ihrer Seriennummer unterscheiden können. Es sind also nur bestimmte Anzahlen an Solarzellen pro Solarmodul zulässig. Seriennummer, die Anzahl der Solarzellen und die Leistung des gesamten Solarmodul sollen sich abfragen lassen. - einzelne Solarzellen in einem Modul können verschattet sein. Früher brach dann die Leistung des gesamten Moduls komplett ein. Ein findiger Ingenieur hat eine technische Lösung dafür entwickelt. Damit er die auch umsetzen kann, muss man herausfinden können, wie viele Solarzellen in einem Modul gerade verschattet sind. Bei Verschattung bricht die Spannung einer Solarzelle auf unter 0,3V ein. Erweitere die Klasse "solarmodule" um eine entsprechende Methode, die die Anzahl der verschatteten Solarzellen zurückgibt. === Tipps === Du musst dir für ein Solarmodul immer sehr viele Solarzellen erzeugen. Am besten geht das mit einem Array von Solarzellen, dass du mit einer Methode erzeugen kannst. Ob du das im Hauptprogramm oder innerhalb der Klasse "solarmodule" machst, ist im Prinzip gleichwertig. ++++ Klicke hier für einen Lösungsansatz | import random class solarmodule: def __init__(self, serial, watts): # Wenn die Wattwerte stimmen - Objekt bauen if (watts == 120) or (watts == 210) or (watts == 390): self.watts = float(watts) self.cells = self.buildCellArray() # Sonst mit Fehlermeldung abbrechen else: print("Modulecreation not successful!") quit() self.serial = serial # Modul mit Zellen füllen def buildCellArray(self): # Anzahl der Zellen aus der Wattzahl errechnen cellCount = self.watts/0.6 # Array für Zellen erzeugen cells = [] # Array mit Zellobjekten füllen for i in range(int(cellCount)): cells.append(solarcell(i,0.6)) return cells # Zufällige Zelle unter 0.6 Volt setzen # Count gibt die Anzahl der zu veränderenden Zellen an def shadowCells(self, count): for j in range(count): # Wende auf eine zufällige Zelle die Methode "setCurrent" an, die Zelle wird von der Hilfsmethode returnRandomElement() zurückgegeben # Das ist eine üble Zeile, daher nochmal langsam: # self : Schlüsselwort, dass die Methode returnRandomElement() des aktuellen Objekts aufgerufen werden soll # returnRandomElement(self.cells) : Aufruf der Methode, Übergabe des Zellarrays. Die Methode returnRandomElement() nimmt gibt eine zufällige Zelle zurück # setCurrent(0.2) : Auf diese Zelle wird die Methode setCurrent() der Klasse solarcell angewendet # Also kurz : "Setze die aktuelle Spannung einer beliebigen Zelle auf 0.2V." self.returnRandomElement(self.cells).setCurrent(0.2) # Anzahl der momentan verschatteten Zellen zurückgeben def returnShadowedCells(self): count = 0 for h in range(len(self.cells)-1): if self.cells[h].actualCurrent < 0.6: count += 1 return count # Hilfsmethode: Eine zufällige Zelle zurückgeben def returnRandomElement(self, array): zufallszahl = random.randint(0,len(array)-1) return array[zufallszahl] class solarcell: def __init__(self, id, actualCurrent): self.id = id self.actualCurrent = actualCurrent # Methode zum Setzen der Zellspannung (current) def setCurrent(self, current): self.actualCurrent = current # Some Testing # Modul erzeugen module01 = solarmodule(1, 390) # Modul mit zufälliger Anzahl verschatteter Zellen ausstatten module01.shadowCells(random.randint(0,100)) # Anzahl der verschatteten Zellen ausgeben print(f'Es gibt gerade {module01.returnShadowedCells()} verschattete Zellen.' ) ++++