Files
wbs-python/python/klassen.ipynb
T
2026-07-22 12:04:02 +02:00

932 lines
27 KiB
Plaintext

{
"cells": [
{
"metadata": {},
"cell_type": "markdown",
"source": [
"# Klassen, Vererbung und Magic Methods in Python\n",
"\n",
"## Ziel dieser Einheit\n",
"\n",
"In dieser Einheit lernst du:\n",
"\n",
"- wie Klassen in Python aufgebaut sind\n",
"- wie Klassenattribute und Instanzattribute funktionieren\n",
"- wie Properties verwendet werden\n",
"- wie Klassenmethoden und statische Methoden unterschieden werden\n",
"- wie Vererbung und Mehrfachvererbung in Python funktionieren\n",
"- wie Konstruktorverkettung mit super() und \\*args umgesetzt wird\n",
"- wie Magic Methods verwendet werden"
],
"id": "1bc0f92c24d3aafd"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 1. Überblick über das Beispiel\n",
"\n",
"Dieses Thema besteht aus zwei Beispielen.\n",
"\n",
"### Beispiel 1: Klassen und Vererbung\n",
"\n",
"Das erste Beispiel besteht aus den Dateien:\n",
"\n",
"- computer.py\n",
"- telefon.py\n",
"- smartphone.py"
],
"id": "25e3da34ffcde469"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-21T08:17:20.833561200Z",
"start_time": "2026-07-21T08:17:20.769251100Z"
}
},
"cell_type": "code",
"source": [
"from telefon import Telefon\n",
"from computer import Computer\n",
"from smartphone import Smartphone\n",
"from fraction import Fraction"
],
"id": "57dce3cccdaf835a",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Environment computer\n"
]
}
],
"execution_count": 1
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"In diesen Dateien wird gezeigt:\n",
"\n",
"- wie Klassen definiert werden\n",
"- wie Attribute gekapselt werden\n",
"- wie Properties funktionieren\n",
"- wie Klassenmethoden und statische Methoden verwendet werden\n",
"- wie Vererbung funktioniert\n",
"- wie Python Mehrfachvererbung ermöglicht\n",
"- wie Konstruktoren über super() verkettet werden"
],
"id": "a8ebda0b94eb34a8"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"### Beispiel 2: Magic Methods\n",
"\n",
"Das zweite Beispiel besteht aus der Datei:\n",
"\n",
"- fraction.py\n",
"\n",
"Hier wird gezeigt:\n",
"\n",
"- wie Operatoren über Magic Methods angepasst werden können\n",
"- wie Objekte mit print() sinnvoll ausgegeben werden können\n",
"- wie Objekte gelöscht werden können"
],
"id": "577ba96741997bd"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"### Main-Datei\n",
"\n",
"Die Datei klassen.py verwendet die Klassen aus beiden Beispielen und zeigt, wie die Konzepte praktisch genutzt werden."
],
"id": "b9023a06c19885c0"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## 2. Die Klasse Computer",
"id": "1df322274c512733"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"Die Datei computer.py beginnt mit der Definition der Klasse Computer.\n",
"\n",
" class Computer:\n",
"\n",
" anzahl = 0\n",
"\n",
"Das Attribut anzahl ist ein Klassenattribut.\n",
"\n",
"Ein Klassenattribut gehört nicht zu einem einzelnen Objekt, sondern zur Klasse selbst. Dadurch teilen sich alle Objekte der Klasse Computer dieses Attribut.\n",
"\n",
"In diesem Beispiel wird anzahl verwendet, um zu zählen, wie viele Computer-Objekte erzeugt wurden."
],
"id": "b1d89c1b6e8c4c93"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## 3. Initialisierung eines Computer-Objekts",
"id": "b6b287aaf94bd2a3"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-21T08:17:40.156907400Z",
"start_time": "2026-07-21T08:17:40.096922700Z"
}
},
"cell_type": "code",
"source": [
"computer = Computer(\"Dell\")\n",
"print(computer.bezeichnung)\n",
"computer.bezeichnung = \"Asus\"\n",
"print(computer.bezeichnung)\n",
"computer.ausgabe_anzahl()"
],
"id": "230073769e0d285",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dell\n",
"Asus\n",
"Anzahl: 2 Computer\n"
]
}
],
"execution_count": 5
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"Wenn Computer() aufgerufen wird, arbeiten in Python \\_\\_new\\_\\_ und \\_\\_init\\_\\_ zusammen.\n",
"\n",
"- \\_\\_new\\_\\_ erzeugt das Objekt\n",
"- \\_\\_init\\_\\_ initialisiert das bereits erzeugte Objekt\n",
"\n",
"Das Attribut \\_\\_bezeichnung wird als privates Attribut angelegt. Die zwei Unterstriche vor dem Namen sorgen dafür, dass Python den Namen intern verändert. Dadurch wird der direkte Zugriff von außen erschwert.\n",
"\n",
"Mit self.\\_\\_class\\_\\_.anzahl wird über das Objekt auf die Klasse zugegriffen. Dadurch kann das Klassenattribut anzahl erhöht werden.\n",
"\n",
"Der Aufruf super().\\_\\_init\\_\\_(\\*args) ist besonders wichtig für die spätere Vererbung. Dadurch kann der nächste Konstruktor in der Vererbungskette aufgerufen werden."
],
"id": "101ad80eb05e2a17"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 4. Property für bezeichnung\n",
"\n",
" @property\n",
" def bezeichnung(self) -> str:\n",
" return self.__bezeichnung\n",
"\n",
"Mit @property wird eine Methode so nutzbar, als wäre sie ein normales Attribut.\n",
"\n",
"Dadurch kann später geschrieben werden:\n",
"\n",
" print(computer.bezeichnung)\n",
"\n",
"Obwohl der Zugriff wie ein einfacher Attributzugriff aussieht, wird intern die Methode bezeichnung() ausgeführt.\n",
"\n",
"So kann ein privates Attribut kontrolliert nach außen verfügbar gemacht werden."
],
"id": "f1f0ea837a0bb5f3"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 5. Setter für bezeichnung\n",
"\n",
" @bezeichnung.setter\n",
" def bezeichnung(self, bezeichnung:str) -> None:\n",
" self.__bezeichnung = bezeichnung\n",
"\n",
"Der Setter wird aufgerufen, wenn der Property ein neuer Wert zugewiesen wird.\n",
"\n",
"Beispiel:\n",
"\n",
" computer.bezeichnung = \"Asus\"\n",
"\n",
"Dadurch wird nicht direkt von außen auf \\_\\_bezeichnung zugegriffen. Stattdessen wird die Setter-Methode ausgeführt und weist den neuen Wert intern zu."
],
"id": "cc788b3ce7d85d75"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 6. Klassische Getter- und Setter-Methoden\n",
"\n",
" def get_bezeichnung(self):\n",
" return self.__bezeichnung\n",
"\n",
" def set_bezeichnung(self, bezeichnung):\n",
" self.__bezeichnung = bezeichnung\n",
"\n",
"Neben Properties können auch klassische Getter- und Setter-Methoden verwendet werden.\n",
"\n",
"Diese Schreibweise erinnert stärker an Java oder C#."
],
"id": "f34bf45c7487532c"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 7. Property mit property()\n",
"\n",
" bezeichnung_property = property(fget=get_bezeichnung, fset=set_bezeichnung)\n",
"\n",
"Mit property() können selbst erstellte Getter- und Setter-Methoden zu einer Property verbunden werden.\n",
"\n",
"Diese Variante gilt als veraltet und wird heute normalerweise nicht mehr verwendet.\n",
"\n",
"Stattdessen sollte @property verwendet werden, weil diese Schreibweise lesbarer und moderner ist.\n",
"\n",
"Weitere Informationen:\n",
"https://realpython.com/python-property/"
],
"id": "e39f2e3c37dcff98"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 8. Klassenmethode\n",
"\n",
" @classmethod\n",
" def ausgabe_anzahl(cls):\n",
" print(\"Anzahl: %s Computer\" % cls.anzahl)\n",
"\n",
"Python unterscheidet zwischen Klassenmethoden und statischen Methoden.\n",
"\n",
"Eine Klassenmethode bekommt als ersten Parameter cls.\n",
"\n",
"cls steht für die Klasse selbst. Dadurch kann eine Klassenmethode auf Klassenattribute zugreifen.\n",
"\n",
"In diesem Beispiel greift die Methode ausgabe_anzahl() auf das Klassenattribut anzahl zu und gibt aus, wie viele Computer-Objekte erzeugt wurden."
],
"id": "5781caf27da1f28b"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 9. Das \\_\\_name\\_\\_-Konzept\n",
"\n",
" if __name__ == \"__main__\":\n",
" print(\"Environment main\")\n",
"\n",
" if __name__ == \"computer\":\n",
" print(\"Environment computer\")\n",
"\n",
"Mit \\_\\_name\\_\\_ kann geprüft werden, in welchem Kontext eine Python-Datei ausgeführt wird.\n",
"\n",
"Wenn eine Datei direkt gestartet wird, befindet sie sich in der \\_\\_main\\_\\_-Umgebung.\n",
"\n",
"Wenn die Datei aus einer anderen Datei importiert wird, entspricht \\_\\_name\\_\\_ dem Namen des Moduls.\n",
"\n",
"In diesem Beispiel bedeutet das:\n",
"\n",
"- direkte Ausführung von computer.py → \\_\\_name\\_\\_ ist \"\\_\\_main\\_\\_\"\n",
"- Import aus klassen.py → \\_\\_name\\_\\_ ist \"computer\""
],
"id": "c097e674bee7704d"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## 10. Die Klasse Telefon",
"id": "97d671aeb0d77966"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-21T08:17:20.916537800Z",
"start_time": "2026-07-21T08:17:20.875642500Z"
}
},
"cell_type": "code",
"source": [
"meintelefon = Telefon(\"Vodafone\")\n",
"print(meintelefon.netz)\n",
"meintelefon.klingeln(5)"
],
"id": "32cce4b29f6cbfe6",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vodafone\n",
"*klingel**klingel**klingel**klingel**klingel*\n"
]
}
],
"execution_count": 3
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"Die Datei telefon.py definiert die Klasse Telefon.\n",
"\n",
" class Telefon:\n",
"\n",
" def __init__(self, netz:str, *args):\n",
" self.__netz = netz\n",
" super().__init__(*args)\n",
"\n",
"Auch hier wird im Konstruktor ein privates Attribut gesetzt.\n",
"\n",
"Das Attribut \\_\\_netz speichert das Mobilfunknetz.\n",
"\n",
"Der Aufruf super().\\_\\_init\\_\\_(\\*args) ist wichtig, damit diese Klasse später sauber an der Konstruktorverkettung teilnehmen kann."
],
"id": "1857652c023df901"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 11. Property für netz\n",
"\n",
" @property\n",
" def netz(self) -> str:\n",
" return self.__netz\n",
"\n",
" @netz.setter\n",
" def netz(self, netz:str):\n",
" self.__netz = netz\n",
"\n",
"Die Property netz ermöglicht kontrollierten Zugriff auf das private Attribut \\_\\_netz.\n",
"\n",
"Auch hier sieht der spätere Zugriff wie ein normaler Attributzugriff aus:\n",
"\n",
" print(telefon.netz)\n",
"\n",
"Intern wird aber die Getter-Methode aufgerufen."
],
"id": "ed2fb4ce1225951b"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 12. Statische Methode\n",
"\n",
" @staticmethod\n",
" def klingeln(anzahl:int = 1):\n",
" print(anzahl * \"*klingel*\")\n",
"\n",
"Python unterscheidet zwischen Klassenmethoden und statischen Methoden.\n",
"\n",
"Eine statische Methode bekommt weder self noch cls.\n",
"\n",
"Das bedeutet:\n",
"\n",
"- sie arbeitet nicht mit einem konkreten Objekt\n",
"- sie greift nicht auf Klassenattribute zu\n",
"- sie ist eher eine Hilfsmethode, die logisch zur Klasse gehört\n",
"\n",
"Die Methode klingeln() gibt den Text \"*klingel*\" mehrfach aus.\n",
"\n",
"Der Parameter anzahl hat den Standardwert 1. Wird kein Wert übergeben, klingelt es also einmal."
],
"id": "608e80850e7e02ad"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## 13. Die Klasse Smartphone",
"id": "19e20783d3533b6b"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-21T08:18:01.661401800Z",
"start_time": "2026-07-21T08:18:01.599246Z"
}
},
"cell_type": "code",
"source": [
"galaxy = Smartphone(\"Galaxy\", \"Telekom\")\n",
"\n",
"print(galaxy.bezeichnung)\n",
"print(galaxy.netz)\n",
"galaxy.klingeln(5)\n",
"galaxy.ausgabe_anzahl()\n",
"\n",
"#galaxy.__class__ = Telefon # Datentyp des Objektes ändern\n",
"#galaxy: Telefon = galaxy # Datentyp der Variable ändern\n",
"print(type(galaxy))\n",
"\n",
"# Wie bei Java und C# können wir prüfen, ob das Objekt vom Typ Smartphone auch ein Objekt vom Typ Telefon ist:\n",
"if isinstance(galaxy, Telefon):\n",
" print(galaxy.bezeichnung + \" ist ein Telefon.\")"
],
"id": "23d06b73f3563f9",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Galaxy\n",
"Telekom\n",
"*klingel**klingel**klingel**klingel**klingel*\n",
"Anzahl: 3 Computer\n",
"<class 'smartphone.Smartphone'>\n",
"Galaxy ist ein Telefon.\n"
]
}
],
"execution_count": 6
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"Die Datei smartphone.py importiert zunächst die Klassen Telefon und Computer.\n",
"\n",
" from telefon import Telefon\n",
" from computer import Computer\n",
"\n",
"Anschließend wird die Klasse Smartphone definiert.\n",
"\n",
" class Smartphone(Computer, Telefon):\n",
" def __init__(self, bezeichnung:str, netz:str, *args):\n",
" super().__init__(bezeichnung, netz, *args)\n",
"\n",
"Python kann Mehrfachvererbung.\n",
"\n",
"Das bedeutet, dass eine Klasse von mehreren Klassen erben kann.\n",
"\n",
"In diesem Beispiel erbt Smartphone von:\n",
"\n",
"- Computer\n",
"- Telefon\n",
"\n",
"Die Reihenfolge ist wichtig:\n",
"\n",
" class Smartphone(Computer, Telefon)\n",
"\n",
"Dadurch wird zuerst Computer und danach Telefon in die Vererbungskette aufgenommen."
],
"id": "a2ae80c347f18d49"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 14. Konstruktorverkettung\n",
"\n",
"In der Main-Datei wird ein Smartphone erzeugt.\n",
"\n",
" galaxy = Smartphone(\"Galaxy\", \"Telekom\")\n",
"\n",
"Die Werte \"Galaxy\" und \"Telekom\" werden an den Konstruktor von Smartphone übergeben.\n",
"\n",
"Dort werden sie über super().\\_\\_init\\_\\_ an die Konstruktoren der Superklassen weitergeleitet.\n",
"\n",
"Da Smartphone von mehreren Klassen erbt, werden auch die Konstruktoren der Superklassen verkettet."
],
"id": "5e9624a25fca2221"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 15. Ablauf der Konstruktorverkettung\n",
"\n",
"Der Ablauf sieht vereinfacht so aus:\n",
"\n",
"1. Smartphone erhält bezeichnung und netz\n",
"2. Smartphone ruft super().\\_\\_init\\_\\_(bezeichnung, netz, \\*args) auf\n",
"3. Computer erhält bezeichnung und nimmt netz über \\*args entgegen\n",
"4. Computer speichert die Bezeichnung\n",
"5. Computer ruft super().\\_\\_init\\_\\_(\\*args) auf\n",
"6. Telefon erhält netz\n",
"7. Telefon speichert das Netz\n",
"\n",
"Damit das funktioniert, benötigen die Konstruktoren zusätzliche Parameter über \\*args.\n",
"\n",
"\\*args steht für eine beliebige Anzahl weiterer Parameter.\n",
"\n",
"Dadurch können Parameter, die eine Klasse nicht selbst verarbeitet, an die nächste Klasse weitergegeben werden."
],
"id": "43df21a4d5bb3d00"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 16. Reihenfolge bei Mehrfachvererbung\n",
"\n",
"Die Reihenfolge der Konstruktorverkettung wird durch die Reihenfolge bei der Vererbung bestimmt.\n",
"\n",
" class Smartphone(Computer, Telefon)\n",
"\n",
"In diesem Beispiel wird zuerst Computer und danach Telefon berücksichtigt.\n",
"\n",
"Theoretisch kann Python von beliebig vielen Klassen erben. Damit auch Smartphone für weitere Vererbungen offen bleibt, enthält auch dessen Konstruktor \\*args."
],
"id": "98bbbe3c61a5aaec"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 17. Die Main-Datei klassen.py\n",
"\n",
"In klassen.py werden die benötigten Klassen importiert.\n",
"\n",
" from telefon import Telefon\n",
" from computer import Computer\n",
" from smartphone import Smartphone\n",
" from fraction import Fraction\n",
"\n",
"Diese Datei dient als Einstiegspunkt, um die Klassen zu erzeugen und zu testen."
],
"id": "627021ed917b1fd4"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 18. Arbeiten mit Computer\n",
"\n",
" computer = Computer(\"Dell\")\n",
" print(computer.bezeichnung)\n",
" computer.bezeichnung = \"Asus\"\n",
" print(computer.bezeichnung_property)\n",
" computer.ausgabe_anzahl()\n",
"\n",
"Computer(\"Dell\") ist der Konstruktor-Ausdruck.\n",
"\n",
"Durch diesen Aufruf werden \\_\\_new\\_\\_ und \\_\\_init\\_\\_ ausgeführt.\n",
"\n",
"Danach wird:\n",
"\n",
"- die Bezeichnung über die Property ausgegeben\n",
"- die Bezeichnung über den Setter verändert\n",
"- die ältere property()-Variante verwendet\n",
"- die Klassenmethode ausgabe_anzahl() aufgerufen"
],
"id": "51f9501545956fda"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 19. Arbeiten mit Telefon\n",
"\n",
" telefon = Telefon(\"1&1\")\n",
" print(telefon.netz)\n",
" telefon.klingeln(10)\n",
"\n",
"Hier wird ein Telefon-Objekt erzeugt.\n",
"\n",
"Danach wird:\n",
"\n",
"- das Netz über die Property ausgegeben\n",
"- die statische Methode klingeln() aufgerufen"
],
"id": "6d7d2d9f239f9775"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 20. Arbeiten mit Smartphone\n",
"\n",
" galaxy = Smartphone(\"Galaxy\", \"Telekom\")\n",
"\n",
"Anschließend können Eigenschaften und Methoden aus beiden Superklassen verwendet werden.\n",
"\n",
" print(galaxy.bezeichnung)\n",
" print(galaxy.netz)\n",
" galaxy.klingeln(5)\n",
" galaxy.ausgabe_anzahl()\n",
"\n",
"Das Smartphone besitzt dadurch:\n",
"\n",
"- bezeichnung aus Computer\n",
"- netz aus Telefon\n",
"- klingeln() aus Telefon\n",
"- ausgabe_anzahl() aus Computer"
],
"id": "4947b906a0f8dc37"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 21. Typprüfung\n",
"\n",
" print(type(galaxy))\n",
"\n",
"Mit type() kann der tatsächliche Typ eines Objekts ausgegeben werden.\n",
"\n",
"---\n",
"\n",
" if isinstance(galaxy, Telefon):\n",
" print(galaxy.bezeichnung + \" ist ein Telefon.\")\n",
"\n",
"Mit isinstance() kann geprüft werden, ob ein Objekt von einem bestimmten Typ ist.\n",
"\n",
"Wie bei Java und C# kann also geprüft werden, ob ein Smartphone auch ein Telefon ist.\n",
"\n",
"Da Smartphone von Telefon erbt, ist diese Prüfung wahr."
],
"id": "b2d9fe72fe34c1aa"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 22. Magic Methods\n",
"\n",
"Die Datei fraction.py behandelt Operatoren und magische Methoden.\n",
"\n",
" class Fraction:\n",
" def __init__(self, numerator:int, denominator:int):\n",
" self.numerator = numerator\n",
" self.denominator = denominator\n",
"\n",
"Magic Methods sind besondere Methoden in Python.\n",
"\n",
"Sie beginnen und enden mit doppelten Unterstrichen.\n",
"\n",
"Beispiele:\n",
"\n",
"- \\_\\_init\\_\\_\n",
"- \\_\\_add\\_\\_\n",
"- \\_\\_str\\_\\_\n",
"- \\_\\_del\\_\\_\n",
"\n",
"Python ruft diese Methoden in bestimmten Situationen automatisch auf.\n",
"\n",
"Weitere Informationen:\n",
"https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types"
],
"id": "92201737e56fe54f"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 23. Ausgabe eines Bruchs\n",
"\n",
" def ausgabe(self):\n",
" print(self.numerator, \"/\", self.denominator)\n",
"\n",
"Diese Methode gibt den Bruch in einer einfachen Schreibweise aus."
],
"id": "1792691e48453934"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 24. Addition mit \\_\\_add\\_\\_\n",
"\n",
" def __add__(self, other):\n",
" numerator = self.numerator * other.denominator + other.numerator * self.denominator\n",
" denominator = self.denominator * other.denominator\n",
" return Fraction(numerator, denominator)\n",
"\n",
"Die Methode \\_\\_add\\_\\_ erlaubt es, zwei Objekte miteinander zu addieren.\n",
"\n",
"Dadurch kann später geschrieben werden:\n",
"\n",
" fraction3 = fraction + fraction2\n",
"\n",
"Python erkennt den Plus-Operator und ruft intern die Methode \\_\\_add\\_\\_ auf."
],
"id": "b2c2c453b68b781b"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 25. String-Darstellung mit \\_\\_str\\_\\_\n",
"\n",
" def __str__(self):\n",
" return str(self.numerator) + \"/\" + str(self.denominator)\n",
"\n",
"Die Methode \\_\\_str\\_\\_ entspricht der ToString()-Methode aus Java oder C#.\n",
"\n",
"Sie bestimmt, wie ein Objekt als String dargestellt wird.\n",
"\n",
"Wenn print(fraction) aufgerufen wird, verwendet Python diese Methode."
],
"id": "22a1c8d454e1b8fe"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 26. Destruktor mit \\_\\_del\\_\\_\n",
"\n",
" def __del__(self):\n",
" print(self.__class__)\n",
"\n",
"Die Methode \\_\\_del\\_\\_ ist der Destruktor.\n",
"\n",
"Sie wird aufgerufen, wenn ein Objekt gelöscht wird."
],
"id": "91b57a5ccbbe0c72"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 27. Arbeiten mit Fraction\n",
"\n",
" fraction = Fraction(5, 10)\n",
" fraction.ausgabe()\n",
" print(fraction)\n",
" print(fraction.__dict__)\n",
"\n",
"Hier wird ein Fraction-Objekt erzeugt.\n",
"\n",
"Danach wird:\n",
"\n",
"- der Bruch mit der eigenen Methode ausgegeben\n",
"- der Bruch mit print() ausgegeben\n",
"- das interne Dictionary des Objekts angezeigt\n",
"\n",
"\\_\\_dict\\_\\_ zeigt die Attribute, die im Objekt gespeichert sind."
],
"id": "6cac29b8e80971d"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 28. Zweiter Bruch und Addition\n",
"\n",
" fraction2 = Fraction(1, 2)\n",
" print(fraction2)\n",
"\n",
" fraction3 = fraction + fraction2\n",
" fraction3.ausgabe()\n",
" print(fraction3)\n",
"\n",
"Hier werden zwei Fraction-Objekte addiert.\n",
"\n",
"Durch die Methode \\_\\_add\\_\\_ kann der Plus-Operator verwendet werden."
],
"id": "e5f8d6898b990069"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 29. Objekte löschen\n",
"\n",
" del fraction\n",
" fraction2 = None\n",
" print(\"Zwei Objekte sind gelöscht\")\n",
"\n",
"Mit del wird ein Objekt manuell gelöscht.\n",
"\n",
"Wenn eine Variable auf None gesetzt wird und keine weiteren Referenzen mehr auf das Objekt zeigen, kann das Objekt ebenfalls gelöscht werden."
],
"id": "23c8e0a5a89f5a40"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## 30. Wichtige Konzepte im Überblick\n",
"\n",
"### Klassen\n",
"\n",
"Klassen bündeln Daten und Verhalten.\n",
"\n",
"---\n",
"\n",
"### Instanzattribute\n",
"\n",
"Instanzattribute gehören zu einem konkreten Objekt.\n",
"\n",
"---\n",
"\n",
"### Klassenattribute\n",
"\n",
"Klassenattribute gehören zur Klasse und werden von allen Objekten geteilt.\n",
"\n",
"---\n",
"\n",
"### Properties\n",
"\n",
"Properties ermöglichen kontrollierten Zugriff auf Attribute, sehen aber aus wie normale Variablen.\n",
"\n",
"---\n",
"\n",
"### Klassenmethoden\n",
"\n",
"Klassenmethoden erhalten cls und können auf Klassenattribute zugreifen.\n",
"\n",
"---\n",
"\n",
"### Statische Methoden\n",
"\n",
"Statische Methoden erhalten weder self noch cls.\n",
"\n",
"---\n",
"\n",
"### Vererbung\n",
"\n",
"Vererbung ermöglicht Wiederverwendung von Code.\n",
"\n",
"---\n",
"\n",
"### Mehrfachvererbung\n",
"\n",
"Python erlaubt Vererbung von mehreren Klassen.\n",
"\n",
"---\n",
"\n",
"### Konstruktorverkettung\n",
"\n",
"Konstruktorverkettung bedeutet, dass Konstruktoren mehrerer Klassen nacheinander aufgerufen werden.\n",
"\n",
"---\n",
"\n",
"### Magic Methods\n",
"\n",
"Magic Methods definieren besonderes Verhalten, zum Beispiel für Operatoren oder print()."
],
"id": "91e7a78416a01a31"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## Zusammenfassung\n",
"\n",
"- Python-Klassen können Attribute und Methoden enthalten\n",
"- Klassenattribute gelten für alle Objekte einer Klasse\n",
"- Instanzattribute gehören zu einem bestimmten Objekt\n",
"- Properties verbinden Getter und Setter mit Variablenzugriff\n",
"- Python unterstützt Mehrfachvererbung\n",
"- super() und \\*args ermöglichen Konstruktorverkettung\n",
"- Magic Methods erlauben besondere Spracheigenschaften wie Operatoren"
],
"id": "55b53e324eca3645"
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## Verständnisfragen\n",
"\n",
"- Was ist der Unterschied zwischen Klassenattribut und Instanzattribut?\n",
"- Warum wird super() bei Vererbung verwendet?\n",
"- Wofür wird \\*args in den Konstruktoren benötigt?\n",
"- Was passiert bei der Konstruktorverkettung?\n",
"- Wozu dient die Methode \\_\\_add\\_\\_?"
],
"id": "872a30edea3b0c7c"
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}