.vscode
Tutorium
tut01
tut02
tut03
tut04
tut05
tut06
tut07
tut08
tut09
tut10
tut11
tut12
src
README.md
notes.md
slides.pdf
tut13
tut14
src
.gitignore
LICENSE
README.md
marp, paginate, theme, footer, header, math
marp | paginate | theme | footer | header | math |
---|---|---|---|---|---|
true | true | rose-pine | Tutorium 13 - 26.01.2024 - Nils Pukropp - https://s.narl.io/s/tutorium-13 | 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- 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
- aktuell noch nicht online
Link: 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 Typint
eine Ganzzahl - ähnlich zur mathematischen Schreibweise
x \in \mathbb{Z}
- z.B. ist eine Variable
- 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
- wir müssen unsere
- 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: <Type> = ...
- Beispiele:
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: <Type>, param2: <Type>, ...) -> <Type>
- Beispiele:
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: <Type> attribute_name2: <Type> ...
- Beispiel:
@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: <Type>, ...) -> <Type>
- Beispiel:
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 aberother
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 inlist
zu annotierendef 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:
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:
number_dictionary: dict[int, str] = { 0: "zero", 1: "one", 2: "two", }
- Diese Annotation ist verpflichtend
- Diese kann weiter geschachtelt werden durch z.B.
list
alsValue
: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:
def add[T](x: T, y: T) -> T: return x + y
T
kann nur ein Datentyp sein, also musstype(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 durchT: (int, str)
, hierbei istT
entweder einint
oder (exklusiv)str
Fehlerquelle - Was ist TypeVar?
TypeVar
ist aus früheren Python-Versionen- Typvariablen wurden vor der Python 3.12 so definiert:
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
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 ohnedef
- Bietet sich vor allem an für kleine Funktionen und Kompositionen von Funktionen
print(reduce(lambda x, y: x + y, [1, 2, 3, 4])) # 10
- hat als Datentyp auch
Callable
add: Callable[[int, int], int] = lambda x, y: x + y
Closures
- Verkettete Funktionen, bei denen die Variabeln aus vorherigen benutzt werden können
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
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 einemIterable
andef 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
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
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
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