diff --git a/Tutorium/tut12/README.md b/Tutorium/tut12/README.md index aaf86ad..bcf1c8d 100644 --- a/Tutorium/tut12/README.md +++ b/Tutorium/tut12/README.md @@ -3,224 +3,63 @@ marp: true paginate: true # class: invert theme: rose-pine -footer: Tutorium 12 - 19.01.2024 - Nils Pukropp - https://s.narl.io/s/tutorium-12 +footer: Tutorium 13 - 26.01.2024 - Nils Pukropp - https://s.narl.io/s/tutorium-13 header: math: mathjax --- -# Tutorium 12 - 19.01.2024 +# Tutorium 13 - 26.01.2024 -Musterlösung 11 - Wiederholung Types - Functions! +Orga - Wiederholung Types - Functions! - Decorator --- -# Musterlösung - Exercise 11 +# Orga + +--- +## Wegen fehlendem Tutorium am 19.01. + +- Jeder kriegt die 6 Punkte für Anwesenheit + - Auf Blatt 13 als Extrapunkte unter *Anmerkungen* +- Sorry fürs nicht beantworten von manchen Nachrichten +- Falls ihr glaubt ihr bekommt knapp nicht genug Punkte schreibt mich einfach an, man wird schon noch irgendwo Punkte finden --- -# Aufgabe 11.1 - Generatoren; `generators.py` [`10p`] +## Syntax-Fehler + +- Für **Syntax-Fehler** habe ich im allgemeinen **0 Punkte** in der jeweiligen Datei vergeben + - Das euer Programm ausführbar ist sollte das mindeste sein! + - Ihr sollt euer Programm sowieso selbständig testen und ich geh mal davon aus das ist nicht passiert wenn sich die Datei nichtmal ausführen lässt +- Zeitdruck kann ich voll nachvollziehen --- -## Aufgabe 11.1 a - collatz; [`2.5p`] -Es seien $i \in \mathbb{N}_0$ und $n \in \mathbb{N}$, so ist die Collatz-Folge definiert als +## Nachträgliches ausbessern -$$ -\begin{align*} - c_0 &= n \\ - c_{i+1} &= - \begin{cases} - \frac{c_i}{2}, &c_i\mod 2 = 0 \\ - 3 \cdot c_i + 1, &c_i\mod 2 = 1 - \end{cases} -\end{align*} -$$ - -Dabei gilt $c_i = 1$ als Abbruchbedingung des Generators +- Ihr verbessert euren SyntaxFehler (eure Python-Datei ist ausführbar) +- Ihr schickt mir eine `.zip` oder eine `.tar.gz` mit dem verbesserten Code an [nils@narl.io](mailto:nils@narl.io) + - verbessert nichts anderes! + - Schreibt kurz in die Mail welches Blatt + Aufgabe + Kürzel +- Ich korrigiere eure Abgabe nachträglich und ihr bekommt zumindest mehr als 0 Punkte +- Bitte nur wenn ihr wirklich die Punkte braucht und habt etwas Geduld mit der Korrektur --- -## Aufgabe 11.1 a - collatz; [`2.5p`] +## Allgemeines -```python -def collatz(n: int) -> Generator[int, None, None]: - if n < 1: - return - while n > 1: - yield n - if n % 2 == 0: - n = n // 2 - else: - n = 3 * n + 1 - yield n -``` +- biete euch Übungen passend zur Klausur + - kein genaues Datum, aber vor dem 09.02 +- Klausur ist *wahrscheinlich* am 19.02. +- Short-Link zu der Übung [https://s.narl.io/s/eidp-ub](https://s.narl.io/s/eidp-ub) + - aktuell noch nicht online --- -## Aufgabe 11.1 b - random; [`2.5p`] +# Link: [https://s.narl.io/s/eidp-ub](https://s.narl.io/s/eidp-ub) --- -## Aufgabe 11.1 b - random; [`2.5p`] - -```python -def random(seed: int, a: int, b: int, m: int) -> Iterator[int]: - yi = seed - while True: - yield yi - yi = (a * yi + b) % m -``` - ---- - -## Aufgabe 11.1 c - chunks; [`2.5p`] - ---- - -## Aufgabe 11.1 c - chunks; [`2.5p`] - -```python -def chunks[T](iter: Iterator[T], n: int) -> Iterator[list[T]]: - while True: - xs = [] - try: - for _ in range(n): - xs.append(next(iter)) - yield xs - except StopIteration: - if xs: - yield xs - break -``` - ---- - -## Aufgabe 11.1 d - flatten; [`2.5p`] - ---- - -## Aufgabe 11.1 d - flatten; [`2.5p`] - -```python -def flatten[T](iters: Iterator[list[T]]) -> Iterator[T]: - for iter in iters: - yield from iter -``` - ---- - -# Aufgabe 11.2 - Graphen; `graphs.py` [`10p`] - -Typaliase als Hilfestellung -```python -type GDict[T] = dict[T, set[T]] -type Graph[T] = GDict[T] -``` - ---- - -## Aufgabe 11.2 a - is_graph; [`2.5p`] - ---- - -## Aufgabe 11.2 a - is_graph; [`2.5p`] - -```python -def is_graph(d: GDict[Any]) -> bool: - for vals in d.values(): - for val in vals: - if val not in d.keys(): - return False - return True - -``` - ---- - -## Aufgabe 11.2 b - to_graph; [`2.5p`] - ---- - -## Aufgabe 11.2 b - to_graph; [`2.5p`] - -```python -def to_graph[T](d: GDict[T]) -> Graph[T]: - res = dict() - for k, vals in d.items(): - for val in vals: - if val not in d: - res[val] = set() - res[k] = vals - return res -``` - ---- - -## Aufgabe 11.2 c - nodes, edges; [`2.5p`] - ---- - -## Aufgabe 11.2 c - nodes, edges; [`2.5p`] - -```python -def edges[T](graph: Graph[T]) -> Iterator[tuple[T, T]]: - for key, value in graph.items(): - for v in value: - yield (key, v) - - -def nodes[T](graph: Graph[T]) -> Iterator[T]: - yield from graph.keys() -``` - ---- - -## Aufgabe 11.2 d - invert_graph; [`2.5p`] - ---- - -## Aufgabe 11.2 d - invert_graph; [`2.5p`] - -```python -def invert_graph[T](graph: Graph[T]) -> Graph[T]: - res = dict() - for n in nodes(graph): - res[n] = set() - for a, b in edges(graph): - res[b].add(a) - return res -``` - ---- - -## Aufgabe 11.2 e - has_cycle; [`0p`] - ---- - -## Aufgabe 11.2 e - has_cycle; [`0p`] - -```python -def find_cycle[T](graph: Graph[T], start: T, visited: set[T]) -> bool: - assert start in graph - if start in visited: - return True - for value in graph[start]: - if find_cycle(graph, value, visited | {start}): - return True - return False - - -def has_cycle(graph: Graph[Any]) -> bool: - return any(find_cycle(graph, node, set()) for node in graph) -``` - ---- - -## Aufgabe 11.3 - Erfahrungen `NOTES.md`; [`0p`] - -### Tragt eure Stunden ein! - ---- # Type annotations (Wiederholung) @@ -582,4 +421,4 @@ print(add_but_variable(3, 2)) # 5 --- -# Weitere allgemeine Fragen? \ No newline at end of file +# Weitere allgemeine Fragen? diff --git a/Tutorium/tut13/README.md b/Tutorium/tut13/README.md index e69de29..bcf1c8d 100644 --- a/Tutorium/tut13/README.md +++ b/Tutorium/tut13/README.md @@ -0,0 +1,424 @@ +--- +marp: true +paginate: true +# class: invert +theme: rose-pine +footer: Tutorium 13 - 26.01.2024 - Nils Pukropp - https://s.narl.io/s/tutorium-13 +header: +math: mathjax +--- + +# Tutorium 13 - 26.01.2024 + +Orga - Wiederholung Types - Functions! - Decorator + +--- + +# Orga + +--- +## Wegen fehlendem Tutorium am 19.01. + +- Jeder kriegt die 6 Punkte für Anwesenheit + - Auf Blatt 13 als Extrapunkte unter *Anmerkungen* +- Sorry fürs nicht beantworten von manchen Nachrichten +- Falls ihr glaubt ihr bekommt knapp nicht genug Punkte schreibt mich einfach an, man wird schon noch irgendwo Punkte finden + +--- + +## Syntax-Fehler + +- Für **Syntax-Fehler** habe ich im allgemeinen **0 Punkte** in der jeweiligen Datei vergeben + - Das euer Programm ausführbar ist sollte das mindeste sein! + - Ihr sollt euer Programm sowieso selbständig testen und ich geh mal davon aus das ist nicht passiert wenn sich die Datei nichtmal ausführen lässt +- Zeitdruck kann ich voll nachvollziehen + +--- + +## Nachträgliches ausbessern + +- Ihr verbessert euren SyntaxFehler (eure Python-Datei ist ausführbar) +- Ihr schickt mir eine `.zip` oder eine `.tar.gz` mit dem verbesserten Code an [nils@narl.io](mailto:nils@narl.io) + - verbessert nichts anderes! + - Schreibt kurz in die Mail welches Blatt + Aufgabe + Kürzel +- Ich korrigiere eure Abgabe nachträglich und ihr bekommt zumindest mehr als 0 Punkte +- Bitte nur wenn ihr wirklich die Punkte braucht und habt etwas Geduld mit der Korrektur + +--- + +## Allgemeines + +- biete euch Übungen passend zur Klausur + - kein genaues Datum, aber vor dem 09.02 +- Klausur ist *wahrscheinlich* am 19.02. +- Short-Link zu der Übung [https://s.narl.io/s/eidp-ub](https://s.narl.io/s/eidp-ub) + - aktuell noch nicht online + +--- + +# Link: [https://s.narl.io/s/eidp-ub](https://s.narl.io/s/eidp-ub) + +--- + +# Type annotations +(Wiederholung) + +--- + +## Type annotations - Was ist das? + +--- + +## Type annotations - Was ist das? + +* Jedes **Objekt** lässt sich mindestens einem **Typ** zuordnen + * Objekte im mathematischen Sinne wie z.B. Variablen, Funktionen, ... +* Dieser **schränkt** den Wertebereich ein + * z.B. ist eine Variable `x` von Typ `int` eine Ganzzahl + * ähnlich zur mathematischen Schreibweise $x \in \mathbb{Z}$ +* In der Informatik nennt man das **Typisierung** + * Es gibt verschiedene Arten der Typisierung + +--- + +## Type annotations - Typisierung + +- **dynamische Typisierung** überprüft die gegebenen Typen zur **Laufzeit** + - also erst wenn das Programm *läuft* +- **statische Typisierung** überprüft die gegebenen Typen zur **Übersetzungszeit** + - also während wir den Quellcode übersetzen + +--- + +## Type annotations - Typisierung + +- **dynamische Typisierung** überprüft die gegebenen Typen zur **Laufzeit** + - also erst wenn das Programm *läuft* +- **statische Typisierung** überprüft die gegebenen Typen zur **Übersetzungszeit** + - also während wir den Quellcode übersetzen + +### Was ist nun Python? + +--- + +### Was ist nun Python? + +- **dynamisch typisiert** + - wir müssen unsere `.py` Datei ausführen bevor wir wissen ob alles korrekt ist +- **Pylance** ist ein eigenes Programm + - es soll beim Schreiben bereits **Typverletzungen** erkennen + - **unvollständige** Typüberprüfung, es soll nur den Entwickler unterstützen + +--- + +## Variabeln Typannotieren + +* `variable_name: = ...` +* Beispiele: + ```python + x: int = 3 + y: int = 5 + string: str = "Hello World!" + + # aber auch eigene Objekte (OOP) + point: Point = Point(3, 1) + ``` +* diese Annotation ist für uns **optional** + +--- + +## Funktionen Typannotieren + +* `def func_name(param1: , param2: , ...) -> ` +* Beispiele: + ```python + def add(x: int, y: int) -> int: + return x + y + + def div(x: float, y: float) -> Optional[float]: + if y == 0.0: + return None + return x / y + ``` +* diese Annotation ist **verpflichtend** und muss so vollständig wie möglich sein + +--- + +## Klassen Typannotieren + +* + ``` + class ClassName: + attribute_name1: + attribute_name2: + ... + ``` +* Beispiel: + ```python + @dataclass + class Point: + x: int + y: int + ``` +* diese Annotation ist **verpflichtend** und muss so vollständig wie möglich sein + +--- + +## Methoden Typannotieren + +* `def method_name(self, param1: , ...) -> ` +* Beispiel: + ```python + class Point: + x: int + y: int + + def distance_from(self, other: 'Point') -> float: + return math.sqrt((other.x - self.x) ** 2 + (other.y - self.y) ** 2) + ``` +* `self` muss **nicht** Typannotiert werden, kann aber +* `other` hingegen schon, wegen Python muss in der Klasse mit `'` annotiert werden +* diese Annotation ist **verpflichtend** + +--- + +## Datentypen von Datentypen + +* Manche Datentypen bauen sich aus anderen Datentypen auf +* z.B. `list` ist eine Liste von Elementen mit einem Typ +* hierfür verwenden wir `[]` um den Datentyp in `list` zu annotieren + ```python + def sum(xs: list[int]) -> int: + total: int = 0 + for x in xs: + total += x + return total + ``` +* hierbei ist es wichtig so genau wie möglich zu annotieren! +* diese Annotation ist **verpflichtend** + +--- + +## Häufige Fehler mit verschachtelten Typen + +--- + +## Fehlerquelle - `tuple[...]` + +* Tuple haben eine feste größe +* Tuple sind endlich +* Tuple können Elemente mit unterschiedlichen Typen haben +* Die Datentypen der Elemente werden mit einem `,` in `[]` getrennt +* Beispiel: + ```python + tup: tuple[int, int, float, str] = (1, 2, 3.0, "hello world") + ``` +* Diese Annotation ist **verpflichtend** + +--- + +## Fehlerquelle - `dict[...]` + +* Dictionary haben genau zwei zu definierende Typen + * **Key** + * **Value** +* Beispiel: + ```python + number_dictionary: dict[int, str] = { + 0: "zero", + 1: "one", + 2: "two", + } + ``` +* Diese Annotation ist **verpflichtend** +* Diese kann weiter geschachtelt werden durch z.B. `list` als `Value`: + * `dict[int, list[str]]` + +--- + +## Fehlerquelle - Typvariabeln (generische Typen) + +* manchmal wollen wir nicht genau wissen welchen Datentypen wir haben +* dieser wird dann implizit von Python erkannt +* wir stellen damit sicher dass eine Typvariable **beliebig** aber **fest** ist +* Beispiel: + ```python + def add[T](x: T, y: T) -> T: + return x + y + ``` +* `T` kann nur ein Datentyp sein, also muss `type(x) == type(y)` gelten +* **außer** wir schrenken `T` mit `|` ein: `T: (int | str)` damit müssen x und y nicht den gleichen Datentypen haben +* `T` lässt sich weiter einschränken durch `T: (int, str)`, hierbei ist `T` entweder ein `int` oder (exklusiv) `str` + +--- + +## Fehlerquelle - Was ist TypeVar? + +* `TypeVar` ist aus früheren Python-Versionen +* Typvariablen wurden vor der Python 3.12 so definiert: + ```python + T = TypeVar('T') + ``` +* sieht dumm aus, ist es auch, benutzt es nicht! + +--- + +## Fragen zu Typannotationen? + +--- + +# Funktionale Programmierung + +--- + +## Funktionale Programmierung - was ist das? + +- Funktionen sind äquivalent zu Datenobjekten +- anonyme Funktionen aka Lambdas +- Closures +- Programmablauf mit Verkettung und Komposition von Funktionen + +--- + +## Funktionen sind Datenobjekte + +- Jede Funktion hat den Datentyp `Callable` +- Wir können Funktionen wie alle anderen Objekte variabeln zuweisen +```python +def add(a: int, b: int) -> int: + return a + b + +add_but_variable = add + +print(add_but_variable(3, 2)) # 5 +``` + +--- + +## Anonyme Funktionen - `lambda` + +- Mit dem `lambda` Keyword lassen sich anonyme Funktionen definieren ohne `def` +- Bietet sich vor allem an für kleine Funktionen und Kompositionen von Funktionen + ```python + print(reduce(lambda x, y: x + y, [1, 2, 3, 4])) # 10 + ``` +- hat als Datentyp auch `Callable` + ```python + add: Callable[[int, int], int] = lambda x, y: x + y + ``` + +--- + +## Closures + +- Verkettete Funktionen, bei denen die Variabeln aus vorherigen benutzt werden können + ```python + def poly(x: float) -> Callable[[float, float], Callable[[float], float]]: + return lambda a, b: lambda c: a * x ** 2 + b * x + c + + print(poly(3)(2, 3)(5)) # 2 * 3 ** 2 + 3 * 3 + 5 = 32 + ``` +- kein wirklich schönes Beispiel, ein besseres ist `compose` für Kompositionen + +--- + +## Komposition + +- Verketten von Funktionen + ```python + def compose[T](*funcs: Callable[[T], T]) -> Callable[[T], T]: + return fold(lambda f, g: lambda n: f(g(n)), funcs) + + f: Callable[[int], int] = lambda n: n + 42 + g: Callable[[int], int] = lambda n: n ** 2 + h: Callable[[int], int] = lambda n: n - 3 + + print(compose(f, g, h)(0)) + ``` + +--- + +## Higher-Order Functions + +- nehmen eine oder mehrere `Callable` als Argument +- geben ein `Callable` zurück + +### Higher-Order-Function - `map` + +- Wendet ein `Callable` auf jedes Element in einem `Iterable` an + + ```python + def map[T, R](func: Callable[[T], R], xs: Iterable[T]) -> Iterable[R]: + return [func(x) for x in xs] + + numeric_list = list(map(lambda e: int(e), ['1', '2', '3'])) + print(numeric_list) # [1, 2, 3] + ``` + +--- + +### Higher-Order-Function - `filter` + +- `filter` verarbeitet Datenstrukturen anhand eines Prädikats (`Callable`) +- behält nur Elemente die das Prädikat erfüllen + ```python + def filter[T](predicate: Callable[[T], bool], xs: Iterable[T]) -> Iterable[T]: + return [x for x in xs if predicate(x)] + + predicate: Callable[[int | None] bool] = lambda e: e is not None + none_free_list: list[int] = list(filter(predicate, [1, 2, 3, None, 5, 6])) + print(none_free_list) # [1, 2, 3, 5, 6] - kein None + ``` + +--- + +### Higher-Order-Function - `fold` + +- Kombiniert Elemente einer Datenstruktur + ```python + def fold[T](func: Callable[[T, T], T], xs: Iterable[T]) -> T: + it: Iterator[T] = iter(xs) + value: T | None = None + for x in it: + match value: + case None: + value = x + case _: + value = func(value, x) + if not value: + raise TypeError("can't fold empty list") + return value + + sum: Callable[[Iterable[int]], int] = lambda xs: fold(lambda x, y: x + y, xs) + print(sum([1, 2, 3, 4])) # 10 + ``` + +--- + +### keine Higher-Order-Function - `flatten` + +- Nimmt mehrdimensionale Listen und macht eine Liste draus + ```python + def flatten(xs: Iterable[Any]) -> Iterable[Any]: + new_list = [] + for s in xs: + if isinstance(s, Iterable): + new_list += flatten(s) + else: + new_list.append(s) + return new_list + + flattened = list(flatten([[1, 2, 3], 4, [[5, 6], 7, [8, 9]]])) + print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9] + ``` +- nimmt weder `Callable` als Argumente +- gibt kein `Callable` zurück +- ist keine Higher-Order-Function + +--- + +# Fragen zur funktionalen Programmierung? + +--- + +# Weitere allgemeine Fragen? diff --git a/Tutorium/tut13/slides.pdf b/Tutorium/tut13/slides.pdf new file mode 100644 index 0000000..006f4f9 Binary files /dev/null and b/Tutorium/tut13/slides.pdf differ