932 lines
27 KiB
Plaintext
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
|
|
}
|