Unterricht Dienstag
This commit is contained in:
@@ -0,0 +1,931 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
Reference in New Issue
Block a user