Files
Notes/Documents/Arbeit/IFN/Programmieren WiSe 24 25/Jupyter/3.Extended_Applications.ipynb

1662 lines
43 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "1ddc11f3-0a8a-47ee-b7b7-6dfd22ac40d9",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-8c0ecbebdebcad39",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"# Extended Applications: Python Übung\n",
"\n",
"<div style=\"display:flex;\">\n",
" <div style=\"text-align: left\">\n",
" Willkommen zur dritten Programmierübung Einführung in Python 3\n",
" </div>\n",
" <img style=\"float: right; margin: 0px 15px 15px 0px\" src=\"https://www.python.org/static/img/python-logo-large.c36dccadd999.png?1576869008\" width=\"100\" />\n",
"</div>\n",
"\n",
"In dieser Übung werden erweiterte Konzepte gelernt, welche das Konzipieren von Programmen stark vereinfacht.\n",
"\n",
"Wenn Sie Fragen oder Verbesserungsvorschläge zum Inhalt oder Struktur der Notebooks haben, dann können sie eine E-Mail an Phil Keier ([p.keier@hbk-bs.de](mailto:p.keier@hbk-bs.de?subject=[SigSys]%20Feedback%20Programmierübung&amp)) oder Martin Le ([martin.le@tu-bs.de](mailto:martin.le@tu-bs.de?subject=[SigSys]%20Feedback%20Programmierübung&amp)) schreiben.\n",
"\n",
"Link zu einem Python Spickzettel: [hier](https://s3.amazonaws.com/assets.datacamp.com/blog_assets/PythonForDataScience.pdf)\n",
"\n",
"Der Großteil des Python-Tutorials stammt aus der Veranstaltung _Deep Learning Lab_ und von [www.python-kurs.eu](https://www.python-kurs.eu/python3_kurs.php) und wurde für _Signale und Systeme_, sowie _Einführung in die Programmierung für Nicht Informatiker_ angepasst."
]
},
{
"cell_type": "markdown",
"id": "f47e9f08-663b-4c2f-85c7-8b6c7f654b45",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-40ca946ad65b66b6",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"# Konventionen\n",
"\n",
"Python hat einen Grundlegenden Styleguide 2001 von Guido van Rossum festgelegt in [PEP 8](https://peps.python.org/pep-0008/).\n",
"\n",
"Dazu nur ein paar Anmerkungen:\n",
"\n",
"1. Variabel- & Funktionsnamen werden immer kleingeschrieben und mittels \"snake case\" geschrieben. Bsp.: `is_alive`\n",
"2. Zum Einrücken sollten 4 Leerzeichen verwendet werden die mit Tab eingeleitet werden. (Jupyter macht dies Automatisch richtig)\n",
"3. Beim schreiben von Kommentaren folgt nach `#` immer ein Leerzeichen. Bsp.: `# Kommentar`\n",
"4. Importe aus Modulen sollen getrennt sein.\n",
"\n",
" Richtig:\n",
" ```python\n",
" import os\n",
" import sys\n",
" ```\n",
" \n",
" Falsch:\n",
" ```python\n",
" import os, sys\n",
" ```\n",
"\n",
"5. Mehrfach importe aus einem Modul sind dennoch mit `,` gern gesehen.\n",
"\n",
" Bsp.:\n",
" ```python\n",
" from dataclass import dataclass, field, asdict\n",
" ```\n",
"\n",
"6. Nach jedem `,`, `:`(außer beim slicing) und operator `+, =, etc.` folgt ein Leerzeichen.\n",
" \n",
" Bsp.:\n",
" ```python\n",
" x = 4 + 2\n",
" arr[5:10]\n",
" ```\n",
"\n",
"7. Kein unnötiges Ausrichten von Variablen.\n",
"\n",
" So nicht:\n",
" ```python\n",
" x = 4\n",
" y = 5\n",
" name = \"Lisa\"\n",
" ```\n",
"\n",
"8. Die Variablnamen `l` (Kleingeschriebenes L), `O` (Großes o) und `I` (Großes i) sollten niemals als Einzelvariablennamen verwendet werden, da diese Schwer von `i` (Kleines i), `0`(Die Zahl Null) und `L` (Großes L) in einigen Schriftarten zu unterscheiden sind. (Sollte mit Jupyter kein Problem darstellen)"
]
},
{
"cell_type": "markdown",
"id": "4abb5645-0172-4fd7-8f79-02af5140b234",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-ef37f36145723997",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"# Generatoren\n",
"\n",
"Nachdem wir bereits Funktionen kennengelernt haben, welche einen Rückgabewert haben, lernen wir nun ein Python Konzept kennen, dass \"On the fly\" Daten zur Verfügung stellt.\n",
"\n",
"Bisher sind wir davon ausgegangen das beispielweise die Funktion `range` eine Liste zurückgibt. Dies ist vom Gedanken her richtig, dennoch nicht in der Umsetzung.\n",
"\n",
"Mit einem einfachen `print` lässt sich dies auch bestätigen:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "f8f4aee6-ce57-41f8-af18-7256b0126515",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-1e78bfa1751878c9",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"range(0, 10)\n"
]
}
],
"source": [
"print(range(10))"
]
},
{
"cell_type": "markdown",
"id": "dc9f0f52-0a0d-4e5c-8b6f-d7a2b7c5b2e3",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-1c1a0f19a370c840",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Statt wie vielleicht zu erwarten die Liste von werten `0...9` als Ausgabe zu bekommen, gibt uns Python lediglich `range(0, 10)` zurück.\n",
"\n",
"Möchte man die Werte direkt evaluiert haben muss der `*`-Operator verwendet werden:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "89986045-bb47-4bca-b561-bab9bb2b988b",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-723d591c32fda1a7",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 1 2 3 4 5 6 7 8 9\n"
]
}
],
"source": [
"print(*range(10))"
]
},
{
"cell_type": "markdown",
"id": "2248b888-aa12-4367-b1f4-bb4befc43df4",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-19e02ebb63f72a88",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Dabei verändert `range(10)` die `print` Funktion indem es alle Generator Werte als Parameter einsetzt `print(0,1,2,3,4,5,6,7,8,9)` und danach aufruft.\n",
"\n",
"Um selber einen Generator zu definieren benötigt man das Python Keyword `yield`. Im Gegensatz zum Normalen `return` wird die Berechnung nur gestoppt und zu einem späteren Zeitpunkt ausgeführt. Sozusagen hat der Generator ein veränderbaren Zustand.\n",
"\n",
"Die Syntax hierzu ist im Allgemeinen:\n",
"\n",
"```python\n",
"def <funktion-name>(<parameterliste>):\n",
" # do something\n",
" yield <ergebnis>\n",
"```\n",
"\n",
"Eine rudimentäre Funktion `count_to` lässt sich dementsprechend wie folgt definieren:"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "e4686bab-6686-4464-9015-54d420087e5a",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-795ddd785249ca9d",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"This is a Generator: <generator object count_to at 0x1124431c0>\n",
"This Generator evaluates to: 0 1 2 3 4 5 6 7 8 9\n"
]
}
],
"source": [
"def count_to(n):\n",
" count = 0\n",
" while count < n:\n",
" yield count\n",
" count += 1\n",
"\n",
"print(\"This is a Generator:\", count_to(10))\n",
"print(\"This Generator evaluates to:\", *count_to(10))"
]
},
{
"cell_type": "markdown",
"id": "7adfeae1-bab7-42b8-b9f7-39c91cb5db0b",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-ca4e8d2864d7cff7",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Selbiges mit einem For Loop:"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "a19b17c4-144b-4197-8a71-f0554b467564",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-131bc31d10dd26c9",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"This is a Generator: <generator object count_to at 0x112ae1700>\n",
"This Generator evaluates to: 0 1 2 3 4 5 6 7 8 9\n"
]
}
],
"source": [
"def count_to(n):\n",
" for i in range(n):\n",
" yield i\n",
"\n",
"print(\"This is a Generator:\", count_to(10))\n",
"print(\"This Generator evaluates to:\", *count_to(10))"
]
},
{
"cell_type": "markdown",
"id": "7cbdb90b-bedf-4197-97b8-8baf58c92190",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-c2c489efaeeb75dd",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"### Aufgabe\n",
"\n",
"*3 Punkte*\n",
"\n",
"Schreibe einen Generator `square_count` mit einem Eingabeparameter `n`, welcher die Quadratzahlen von $1\\dots n^2$ ausgibt.\n",
"\n",
"Die Aufgabe gibt 0 Punkte, wenn die Funktion `square_count` kein Generator ist!\n",
"\n",
"Hinweis: Bei Eingabe von `5` soll die Ausgabe `1 4 9 16` sein."
]
},
{
"cell_type": "code",
"execution_count": 57,
"id": "2df62e85-d5a5-4664-bdf6-c544ed8fb0d1",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-a037e576943e230b",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [],
"source": [
"# BEGIN SOLUTION\n",
"def square_count(n): \n",
" for i in range(1, n):\n",
" yield i*i\n",
"# END SOLUTION"
]
},
{
"cell_type": "code",
"execution_count": 90,
"id": "234d782c-88f4-4bc2-a872-15a592ee1248",
"metadata": {
"editable": true,
"nbgrader": {
"grade": true,
"grade_id": "cell-a6c43a5365ad736d",
"locked": true,
"points": 3,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Square Numbers from 0 to 1: 1\n",
"Square Numbers from 0 to 2: 1 4\n",
"Square Numbers from 0 to 3: 1 4 9\n",
"Square Numbers from 0 to 4: 1 4 9 16\n",
"Square Numbers from 0 to 5: 1 4 9 16 25\n"
]
}
],
"source": [
"# Hier werden die Loesungen getestet...\n",
"\n",
"# Check if the generator has the right name\n",
"assert \"square_count\" in dir() # 1 Punkt\n",
"\n",
"# Check if square_count is a generator\n",
"import types\n",
"assert isinstance(square_count(1), types.GeneratorType) # 1 Punkt\n",
"\n",
"# Check if the generator generates the right output\n",
"for n in range(10): \n",
" assert [i*i for i in range(1,n)] == [i for i in square_count(n)] # 1 Punkt\n",
"\n",
"# print\n",
"for n in range(2, 7):\n",
" print(f\"Square Numbers from 0 to {n-1}:\", *square_count(n))"
]
},
{
"cell_type": "markdown",
"id": "8e1cb8b2-cdaa-422a-9889-c4e0794d7d81",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-5f6f32fed19a1933",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Generatoren können auch eine unendliche Menge an Daten zurückgeben. Dieses Ziel kann man erreichen indem der Generator unendlich oft ausgeführt wird. Da die Daten zur Laufzeit berechnet werden kann man von einer unendlichen Menge sprechen.\n",
"\n",
"Um eine Berechnung nie enden zu lassen muss die Bedingung der Schleife immer `wahr` bleiben.\n",
"Dies erreicht man durch die Syntax `while True:`, aber Python ist eben Python und die Syntax `while 1:` ist Laufzeit effizienter.\n",
"\n",
"Schauen wir uns nun das Beispiel eines unendlichen Generator an der Fortwährend die nächste Fakultät ausgibt:\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "e7a2e825-b67d-4618-9358-4ee06ef5cc38",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-55717dfe7800e3fb",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"def faktoriel_gen():\n",
" curr = 1\n",
" count = 1\n",
" while 1:\n",
" curr = count * curr\n",
" count += 1\n",
" yield curr"
]
},
{
"cell_type": "markdown",
"id": "496d59e9-e3c1-47d1-982d-8c5688cb7893",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-7d21c6426cee23f0",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Vorsicht (!!) wertet man diesen Generator nun aus würde die Berechnung niemals enden. Um den nächsten Wert der Berechnung zu erhalten hat Python die Funktion `next`, welche den nächsten Zustand des Generators ausgibt. Mit einem `for`-loop und `next` lassen sich dann die Fakultäten der Zahlen bis `5` einfach ausgeben:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "4249c820-f03c-4393-bb8f-5078f9a9a0b8",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-166ede3f392e88e7",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1\n",
"2\n",
"6\n",
"24\n",
"120\n"
]
}
],
"source": [
"gen = faktoriel_gen()\n",
"\n",
"for _ in range(5):\n",
" print(next(gen))"
]
},
{
"cell_type": "markdown",
"id": "8b0d160f-d445-4877-a634-2de69336e70a",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-2e5778830ac74399",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Da der Zustand des Generator gespeichert ist lässt sich mit einem weiteren aufruf in nächster Zelle auf $6! = 720$ ausgeben:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "32e5eb93-507a-490e-9395-717bc7717973",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-30acb8e9a68a7794",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"720\n"
]
}
],
"source": [
"print(next(gen))"
]
},
{
"cell_type": "markdown",
"id": "9901cb74-faf9-47f1-b87e-60d9683778d3",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-3f6a4841c593371f",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"### Aufgabe\n",
"\n",
"*3 Punkte*\n",
"\n",
"Schreibe einen Generator `naturals`, welcher mit jedem Aufruf die nächste natürliche Zahl ausgibt. (Angefangen mit 1)\n",
"\n",
"- Es sind keine Eingabeparameter notwendig.\n",
"- Ist die Funktion kein generator, wird diese Aufgabe mit 0 Punkten bewertet\n",
"\n",
"*Hinweis*: Orientiere dich an dem Beispiel `faktoriel_gen`"
]
},
{
"cell_type": "code",
"execution_count": 60,
"id": "a8b2697c-706b-4744-a4b3-00682d6c95c3",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-09dd94e802cad9bc",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [],
"source": [
"# BEGIN SOLUTION\n",
"def naturals():\n",
" curr = 1\n",
" while 1:\n",
" yield curr\n",
" curr += 1\n",
"# END SOLUTION"
]
},
{
"cell_type": "code",
"execution_count": 91,
"id": "403c70b9-3ac3-4a85-a302-d9c7d0585cbc",
"metadata": {
"editable": true,
"nbgrader": {
"grade": true,
"grade_id": "cell-e065f7326fb561ad",
"locked": true,
"points": 3,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, "
]
}
],
"source": [
"# Hier werden die Loesungen getestet...\n",
"\n",
"# Check if generator is named properly\n",
"assert \"naturals\" in dir() # 1 Punkt\n",
"\n",
"# Check if naturals is a generator\n",
"import types\n",
"assert isinstance(naturals(), types.GeneratorType) # 1 Punkt\n",
"\n",
"# Test if generator works as intended\n",
"import random\n",
"test_n = random.randint(5, 17)\n",
"test_gen = naturals()\n",
"for i in range(1, test_n):\n",
" number = next(test_gen)\n",
" print(number, end=', ')\n",
" assert i == number # 1 Punkt"
]
},
{
"cell_type": "markdown",
"id": "41bb0337-7194-4482-a5b9-af1243d4809c",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-bbe0bad0c47d41ae",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"# Type Hints\n",
"\n",
"Mit [PEP 484](https://peps.python.org/pep-0484/) wurden in Python die `type hints` eingeführt. Die Motivation dafür war es eine Standard Syntax zu definieren, welche einem die Möglichkeit gibt den In- und Output von Funktionen besser zu bestimmen. Unter anderem verbessert sich die Testbarkeit von Python Programmen ungemein wenn Type Hints vorhanden sind. Im Allgemeinen werden `type hints` daher verwendet, um von Variablen und Funktionen die Typen (`int`, `float`, `dict`, etc.) anzuzeigen.\n",
"\n",
"Die Allgemeine Syntax dafür:\n",
"```python\n",
"def <funktions-name>(<parameter1>: <type>, <parameter2>: <type>) -> <output-type>:\n",
" # do something\n",
" return <value of definied output-type>\n",
"```\n",
"\n",
"Python ist eine dynamische typisierte Sprache. Das heißt, dass der Typ einer Variable immer wieder überprüft werden muss. So kann eine Ganzzahl `int` mit einer einfachen addition in eine Flieskommazahl `float` überführt werden:"
]
},
{
"cell_type": "code",
"execution_count": 88,
"id": "d2148990-b5cb-4fe5-8751-bac8338fa581",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-560aa9d85c5a4383",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3 <class 'int'>\n",
"3.14 <class 'float'>\n"
]
}
],
"source": [
"number = 3\n",
"print(number, type(number))\n",
"number += 0.14\n",
"print(number, type(number))"
]
},
{
"cell_type": "markdown",
"id": "56c143f5-1c67-4999-8656-dc68d5912fb4",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-a85903e6bffa1ff1",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Um diese unerwünschten Typenwechsel zu vermeiden, kann man type hints verwenden. Type hints sind nur eine Info keine Garantie das der Typ einer Variable sich ändert!\n",
"\n",
"Eine nutzlose Funktion die den Eingabewert als `int` in einen `str` umwandelt sieht wie folgt aus:"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "642dc60b-fa8d-4655-bc47-815f39365506",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-94708ecde4287ff7",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Number 42\n"
]
}
],
"source": [
"def useless(number: int) -> str:\n",
" return \"Number {}\".format(number)\n",
"\n",
"print(useless(42))"
]
},
{
"cell_type": "markdown",
"id": "ac0a9f33-2e9a-4779-8bf8-1004e6ed7177",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-36dc004fdb6c6682",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Um anzuzeigen das eine Variable einen bestimmten Datentypen zugeordnet ist wird folgende Syntax verwendet:"
]
},
{
"cell_type": "code",
"execution_count": 89,
"id": "e25d2f29-5857-4f0a-93d7-609201e8a0da",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-fdc340bdc4a2000e",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"name: str = \"Peter Parker\""
]
},
{
"cell_type": "markdown",
"id": "777904ec-3567-41c8-a619-2c38ad6b6c51",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-ea3aeed85ff0587c",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"# Dataclasses \n",
"\n",
"Allgemein auf Klassen wird hier nicht eingegangen jedoch ein Konzept, welches mit [PEP 557](https://peps.python.org/pep-0557/) eingeführt wurde, soll folgend stärker beleuchtet werden.\n",
"\n",
"Datenstruckturen wie `dict`, `set`, `list`, etc. sind mächtige Werkzeuge und ermöglichen dem Programmierer Daten in vielen Formen akkurat dazustellen. Möchte man jedoch feste Datenstrukturen mit genau definierten Werten verwenden eignet sich das Modul `dataclasses`.\n",
"\n",
"Dazu wird eine Klasse mit dem Keyword `class` definiert und dem Decorator `dataclasses.dataclass` ausgesattet. Folglich können feste Datenobjekte mit definierter Struktur erstellt werden.\n",
"\n",
"Zunächst wird das Modul aus der Standard Bibliothek importiert:"
]
},
{
"cell_type": "code",
"execution_count": 68,
"id": "24392aea-8ba8-4f9e-ba95-5bf5c99a127b",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-fa6710d8dd259c2d",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"from dataclasses import dataclass"
]
},
{
"cell_type": "markdown",
"id": "abb46684-015f-48c7-98b8-f2955e71de2d",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-36842ee26321c3ec",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Danach kann eine Klasse erstellt werden. Erstellen wir zunächst eine Klasse `Person`, welche die Werte `vorname` und `nachname` als Strings bereitstellen soll:\n",
"\n",
"Wichtig: Python Klassen fangen immer mit einem Großbuchstaben an. Mit Ausnahme der Standard Bibliothek. Die `range` Funktion lässt sich zwar verwenden wie eine Funktion, ist aber eigentlich eine Klasse!"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "b70f39ca-6e57-4b03-a3be-c3b5ac604a9c",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-8b8b2e316c36725c",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"@dataclass\n",
"class Person:\n",
" vorname: str\n",
" nachname: str"
]
},
{
"cell_type": "markdown",
"id": "94901847-a849-463b-968a-b498a9f84edc",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-846dcecf70fd8d14",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Möchten wir nun eine Person erstellen sieht dies wie folgt aus:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "27320011-ee5d-43c9-8e07-fbd3036680f7",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-1cf940f3240bf428",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Person(vorname='Eduard', nachname='Jorswieck') <class '__main__.Person'>\n"
]
}
],
"source": [
"person = Person(\"Eduard\", \"Jorswieck\")\n",
"print(person, type(person))"
]
},
{
"cell_type": "markdown",
"id": "be0c2b13-937e-4073-8dfa-a6d305ed9c6f",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-8338f70364284fc7",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Wie dem Output zu entnehmen ist die Variable `person` ein Objekt vom Typ `Person` und hält die Werte `vorname='Eduard'` und `nachname='Jorswieck'` vor.\n",
"\n",
"Auf die einzelnen Werte innerhalb der Dataclass kann nun per `.` Operator zugegriffen werden:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "191bb87c-06ab-40a4-b5b3-56e9c533b930",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-b6da422f93431723",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vorname: Eduard\n",
"Nachname: Jorswieck\n"
]
}
],
"source": [
"print(\"Vorname:\", person.vorname)\n",
"print(\"Nachname:\", person.nachname)"
]
},
{
"cell_type": "markdown",
"id": "3e85dee5-09ea-4c00-9730-05fb006ced2b",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-d80fa3ef35e81dab",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Dataclasses bieten auch den Vorteil, dass ihre Werte direkt über die Variablennamen definiert werden können. Dabei spielt die Reihenfolge dann keine Rolle mehr."
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "a5ea4ef9-dcba-4411-a2e8-1a1a811e6cac",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-20f0d6f2cb9ef5df",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Person(vorname='Martin', nachname='Le') <class '__main__.Person'>\n"
]
}
],
"source": [
"person2 = Person(nachname=\"Le\", vorname=\"Martin\")\n",
"print(person2, type(person2))"
]
},
{
"cell_type": "markdown",
"id": "68db3f9c-b6ad-4454-87be-71a78a209a40",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-2489e8269aa6414d",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Nicht immer sind alle Werte vorhanden und damit dies nicht zum Problem wird können Standardwerte vergeben werden:"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "ce05d4eb-747b-41ad-9fea-5430b8310e8c",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-92f8a3cacfda2c15",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"@dataclass\n",
"class Person:\n",
" vorname: str = \"Max\"\n",
" nachname: str = \"Mustermann\""
]
},
{
"cell_type": "markdown",
"id": "e4def98c-60a9-4dcf-a71b-6be49f853b3b",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-009056608941f805",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Wird nun eine Dataclass ohne Eingabeparameter erstellt, werden ihr ihre Standardwerte zugewiesen:"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "6d5e0c5d-0f70-4303-83cb-234e9523500c",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-dbc29451821056d9",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Aufruf mit print: Person(vorname='Max', nachname='Mustermann')\n"
]
}
],
"source": [
"nameless_person = Person()\n",
"print(\"Aufruf mit print:\", nameless_person) "
]
},
{
"cell_type": "markdown",
"id": "ccee5184-2f5e-4b90-99ae-2702405c0ec9",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-1c171ff9c43179be",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"### Aufgabe\n",
"\n",
"*6 Punkte*\n",
"\n",
"Schreiben Sie eine Dataclass `Student`\n",
"\n",
"- Die dataclass soll die Werte `vorname`, `nachname`, `semester` und `mat_nr` speichern, vergebe hierzu selber den !!geeigneten!! Datentypen. Mache dir dazu Gedanken ob es Sinnvoll beispielweise die Semesteranzahl als Float zu speichern.\n",
"\n",
"- importiere aus dem dataclasses modul die Funktion `asdict`, erstelle ein Objekt mit den Werten aus dem Beispielstundent, weiße den rückgabewert aus `asdict` aufgerufen mit dem Beispielstudenten der Variablen `stud` zu.\n",
"\n",
"- Die Aufgabe wird mit 0 Punkten bewertet, wenn `Student` keine dataclass ist!\n",
"\n",
"- Hat einer der Attribute keinen geeigneten Datentypen, führt dies nicht zu Punktabzug bei zwei oder mehr schon.\n",
"\n",
"Beispielstudent:\n",
"\n",
"|Attribut|Wert|\n",
"|-|-|\n",
"|vorname|Martin|\n",
"|nachname|Le|\n",
"|mat_nr|520420|\n",
"|semester|5|"
]
},
{
"cell_type": "code",
"execution_count": 75,
"id": "d17b07db-7340-47c0-ab1d-38d75b3194c0",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-ac7d4ba80c4a0341",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [],
"source": [
"# BEGIN SOLUTION\n",
"from dataclasses import asdict\n",
"\n",
"@dataclass\n",
"class Student:\n",
" vorname: str\n",
" nachname: str\n",
" mat_nr: int\n",
" semester: int \n",
"\n",
"stud = asdict(Student(vorname='Martin', nachname='Le', mat_nr=520420, semester=5))\n",
"# END SOLUTION"
]
},
{
"cell_type": "code",
"execution_count": 87,
"id": "ab8dcc00-fc3f-4ae3-a18d-73f97e166ae3",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "cell-10b27d53a9659696",
"locked": true,
"points": 6,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'vorname': 'Martin', 'nachname': 'Le', 'mat_nr': 520420, 'semester': 5}\n"
]
}
],
"source": [
"# Hier werden die Loesungen getestet...\n",
"\n",
"# Check if asdict is imported\n",
"assert \"asdict\" in dir() # 1 Punkt\n",
"\n",
"# Check if Student is named properly\n",
"assert \"Student\" in dir() # 1 Punkt\n",
"\n",
"# Check if Student is a Dataclassimport dataclasses\n",
"from dataclasses import is_dataclass\n",
"assert is_dataclass(Student) # 1 Punkt\n",
"\n",
"# Check if stud is properly converted from Dataclass to dict\n",
"# 3 Punkt\n",
"assert stud == {'vorname': 'Martin', 'nachname': 'Le', 'mat_nr': 520420, 'semester': 5}\n",
"print(stud)"
]
},
{
"cell_type": "markdown",
"id": "448b2019-405f-4f3d-87d4-afa183363a35",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-b8ee343f30f40e1e",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"### Aufgabe\n",
"\n",
"*6 Punkte*\n",
"\n",
"Gegeben sind zwei Listen `colorn` & `colorv_hex`, welche zueinander Index Sortiert sind.\n",
"\n",
"Schreiben nun eine Dataclass `Color` mit den Attributen `name` & `value` und vergebe geeignete Type Hints.\n",
"\n",
"Erstelle danach eine Liste, welche die Werte aus `colorn` & `colorv_hex` in die Dataclass `Color` umwandeln, und speicher die Liste in der variablen `colors`.\n"
]
},
{
"cell_type": "code",
"execution_count": 106,
"id": "27555b53-51e1-48b8-8962-528c22c85b02",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-8fb05db31c5a091d",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [],
"source": [
"colorn = ['RED', 'GREEN', 'BLUE', 'YELLOW', 'PURPLE']\n",
"colorv_hex = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF']"
]
},
{
"cell_type": "code",
"execution_count": 107,
"id": "be9ea7b1-45c4-418d-9a5f-0d101c9fd245",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-dbfa5551c836768a",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[Color(name='RED', value='#FF0000'), Color(name='GREEN', value='#00FF00'), Color(name='BLUE', value='#0000FF'), Color(name='YELLOW', value='#FFFF00'), Color(name='PURPLE', value='#FF00FF')]\n"
]
}
],
"source": [
"colors = None\n",
"# BEGIN SOLUTION\n",
"@dataclass\n",
"class Color:\n",
" name: str\n",
" value: str\n",
"\n",
"colors = [Color(n, w) for n, w in zip(colorn, colorv_hex)]\n",
" \n",
"print(colors)\n",
"# END SOLUTION"
]
},
{
"cell_type": "code",
"execution_count": 108,
"id": "cbf53cfd-7b06-443c-8aca-55463d77aa57",
"metadata": {
"editable": true,
"nbgrader": {
"grade": true,
"grade_id": "cell-a720d5d5ba2ea35c",
"locked": true,
"points": 6,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[Color(name='RED', value='#FF0000'), Color(name='GREEN', value='#00FF00'), Color(name='BLUE', value='#0000FF'), Color(name='YELLOW', value='#FFFF00'), Color(name='PURPLE', value='#FF00FF')]\n"
]
}
],
"source": [
"# Hier werden die Loesungen getestet...\n",
"\n",
"# Check if Color is named properly\n",
"assert \"Color\" in dir() \n",
"\n",
"# Check if Color is a Dataclassimport dataclasses\n",
"from dataclasses import is_dataclass\n",
"assert is_dataclass(Color) # 1 Punkt\n",
"\n",
"# Check if colors is a list\n",
"assert isinstance(colors, list) # 1 Punkt\n",
"\n",
"# Check if colors contains only Color Classes \n",
"for c in colors:\n",
" assert is_dataclass(c) # 1 Punkt\n",
"\n",
"### BEGIN HIDDEN TEST\n",
"@dataclass\n",
"class Color:\n",
" name: str\n",
" value: str\n",
"\n",
"c = [Color(n, w) for n, w in zip(colorn, colorv_hex)]\n",
"for r, s in zip(c, colors):\n",
" assert r.name == s.name\n",
" assert r.value == s.value\n",
"### END HIDDEN TEST\n",
"\n",
"print(colors) # 3 Punkte"
]
},
{
"cell_type": "markdown",
"id": "afe6543a-b41b-4d3c-9929-525a0463c6af",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-a65f2c871406072c",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"# Walrus Operator - Assingment Expressions\n",
"\n",
"Der Grund warum Guido van Rossum das Python Projekt verlassen hat, ist der Walrus Operator `:=`, zu finden unter [PEP 572](https://peps.python.org/pep-0572/). \n",
"\n",
"Das Offizielle Statement:\n",
"\n",
"> \"The straw that broke the camel's back was a very contentious Python enhancement proposal, where after I had accepted it, people went to social media like Twitter and said things that really hurt me personally. And some of the people who said hurtful things were actually core Python developers, so I felt that I didn't quite have the trust of the Python core developer team anymore.\"\n",
"> - Guido van Rossum\n",
"\n",
"Das Problem der Operator `:=` fügt keinerlei neue Funktionalität hinzu und erlaubt einzig und allein eine Zuweisung während einer Auswertung zu erlauben.\n",
"\n",
"Daher ein paar kurze Beispiele, lesen Sie ansonsten gerne PEP 572.\n",
"\n",
"Zuweisung mittels Walrus Operator: (Machen Sie das bitte nicht nach, Niemand wirklich Niemand möchte das sehen!)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "8055d0b2-eb9f-4a1a-ac74-4bfcd6cbee81",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-860f5501722f78aa",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n",
"False\n"
]
}
],
"source": [
"# Normale Zuweisung\n",
"walrus = True\n",
"print(walrus)\n",
"\n",
"# Walrus Zuweisung\n",
"(walrus := False)\n",
"print(walrus)"
]
},
{
"cell_type": "markdown",
"id": "af5f2aab-0e6d-41d8-b3e1-96969a5ad264",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-2fb74418e2478ef5",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Berechnung und Zuweisung in einer Zeile.\n",
"\n",
"Walrus soll verwendet werden, wenn man vermeiden möchte das eine Berechnung zweimal ausgeführt wird.\n",
"\n",
"Beispiel Klassisch `n+1` wird zweimal berechnet:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "b41cae11-20f2-4500-b32a-77775502f6ea",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-85ffa763f1c26ced",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5\n"
]
}
],
"source": [
"n = 4\n",
"if (n + 1) > 3:\n",
" print(n+1)"
]
},
{
"cell_type": "markdown",
"id": "5ad0b0b7-5d85-4a1d-9083-30790c494035",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-da3163fec3bf5f09",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Mit Walrus lässt sich im `if` die Berechnung `n+1` der Variablen `out` zuweisen:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "cde3f827-477c-46d4-8057-af35b694ebef",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-664ab7388a3cb90c",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5\n"
]
}
],
"source": [
"n = 4\n",
"if (out := n + 1) > 3:\n",
" print(out)"
]
},
{
"cell_type": "markdown",
"id": "16375c7c-ef2e-44b7-a5f1-2156248f616c",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-11c8ad1c8ab2ef15",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"Ohne Walrus lässt sich dennoch immer vermeiden die Berechnung `n+1` zweimal auszuführen:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "c1bf6d7e-8ce8-4770-8060-a6d18ab8d85e",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "cell-2dbb33acbcf4f8a4",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5\n"
]
}
],
"source": [
"n = 4\n",
"out = n + 1\n",
"if out > 3:\n",
" print(out)"
]
},
{
"cell_type": "markdown",
"id": "302a6dfd-2e3d-401d-93c9-1335e081e837",
"metadata": {
"editable": true,
"nbgrader": {
"grade": false,
"grade_id": "cell-3254f96c16f5c246",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
},
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"**Persönliche Meinung**: Ich rate davon ab Walrus `:=` zu verwenden. In meinen Augen macht es den Code Grundsätzlich unlesbar und spart im besten Fall 2-3 Zeilen Code. In meiner eigenen Programmiererfahrung gab es nie einen Grund den Operator zu verwenden, er fügte nie einen realen Nutzen in irgendeine meiner Berechnungen ein. Dennoch wollt ich dir einmal Demonstrieren wie Walrus funktioniert."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}