Compare commits
3 Commits
9484d5cb1b
...
main
Author | SHA1 | Date | |
---|---|---|---|
cda9457c27 | |||
8536a1ec88 | |||
c01f023948 |
140
Notes/Unterschiede.md
Normal file
140
Notes/Unterschiede.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# Unterschiede zu Vorjahren
|
||||
|
||||
## Typalias
|
||||
|
||||
Manchmal braucht man eine Kombination aus Datentypen
|
||||
|
||||
### Vorher
|
||||
|
||||
Erstellen von Typaliasen mit `Union`
|
||||
|
||||
```python
|
||||
from typing import Union
|
||||
|
||||
# `RealNumber` ist also eine `int` oder eine `float`
|
||||
RealNumber = Union[int, float]
|
||||
|
||||
# also geht hier
|
||||
# `add(1, 1) -> 2`
|
||||
# `add(1.0, 1.0) -> 2.0`
|
||||
# aber auch
|
||||
# `add(1, 1.0) -> 2.0`
|
||||
def add(x: RealNumber, y: RealNumber) -> RealNumber:
|
||||
return x + y
|
||||
```
|
||||
|
||||
### In Python3.12
|
||||
|
||||
Wir haben jetzt das `type`-Keyword für das wir nichts importieren müssen und können einfach Datentypen mit `|` *odern*
|
||||
|
||||
```python
|
||||
# `type` statt `Union`
|
||||
type NewRealNumber = int | float
|
||||
|
||||
# sonst sieht alles gleich aus
|
||||
def new_add(x: NewRealNumber, y: NewRealNumber) -> NewRealNumber:
|
||||
return x + y
|
||||
```
|
||||
|
||||
## Generiche Typ-Parameter (Generics, Typvariabeln, ...)
|
||||
|
||||
### Vorher
|
||||
|
||||
Erstellen von generischen Typvariabeln/Typ-Parametern mit `TypeVar` aus `typing`:
|
||||
|
||||
```python
|
||||
from typing import Generic, TypeVar, Optional
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
# T ist unser Platzhalten für einen beliebigen Datentyp
|
||||
T = TypeVar('T')
|
||||
|
||||
# jetzt können wir `T` einfach als Platzhalter für einen beliebigen Datentyp verwenden
|
||||
# praktisch weil wir so wissen dass `x`, `y` und der `return` zumindest den **selben** Datentyp verwenden
|
||||
# aber welcher genau wissen wir nicht bis jemand die Funktion mit z.b. `int` oder `float`!
|
||||
# Zum Beispiel bedeutet dass
|
||||
# `add(1, 2) == 3` => `T == int`
|
||||
# `add(1.0, 2.0) == 3.0` => `T == float`
|
||||
# ...
|
||||
def add(x: T, y: T) -> T:
|
||||
return x + y
|
||||
|
||||
# Ebenso können wir `T` auch für Klassen verwenden
|
||||
@dataclass
|
||||
# wir müssen hier festlegen dass T in der Klasse verwendet wird
|
||||
# indem `MyList` von `Generic[UnsereGenerischeVariabel]` erbt
|
||||
class MyList(Generic[T]):
|
||||
|
||||
def __post_init__(self, ):
|
||||
# wir haben intern eine `internal_list` die von außen nicht sichtbar ist
|
||||
self.__internal_list: list[T] = field(default_factory=list)
|
||||
# hier speichern wir uns die aktuelle Länge unserer Liste
|
||||
self.__length: int = 0
|
||||
|
||||
def append(self, value: T):
|
||||
"""fügt ein element mit dem Typ `T` hinzu"""
|
||||
self.__internal_list += [value]
|
||||
self.__length += 1
|
||||
|
||||
def remove(self, value: T):
|
||||
"""entfert das element `value`, wenn es in unserer Liste ist"""
|
||||
if value in self.__internal_list:
|
||||
self.__internal_list.remove(value)
|
||||
|
||||
def get(self, i: int) -> Optional[T]:
|
||||
"""gibt das element an `i` Stelle zurück. Wenn Liste kleiner als `i` ist, dann `None`"""
|
||||
if i < len(self):
|
||||
return self[i]
|
||||
return None
|
||||
|
||||
def __len__(self) -> int:
|
||||
return self.__length
|
||||
|
||||
def __getitem__(self, i: int) -> T:
|
||||
return self.__internal_list[i]
|
||||
```
|
||||
|
||||
### In Python3.12
|
||||
|
||||
Deklaration der Typvariabel direkt im Funktionskopf/Klassenkopf mit `[]`.
|
||||
Sprich wir brauchen `TypeVar` nicht mehr
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
# hier wird `V` durch `[V]` deklariert und kann in der Funktion benutzt werden
|
||||
def new_add[V](x: V, y: V) -> V:
|
||||
return x + y
|
||||
|
||||
|
||||
# hier wird `T` für die Klasse `NewMyList` deklariert durch `[T]` und kann überall in der Klasse genutzt werden
|
||||
# der Rest ist genau gleich, das einzige was sich eben geändert hat ist dass man dieses `TypeVar` nicht mehr braucht
|
||||
# sondern direkt in der Deklaration von Klassen/Funktionen/Methoden die generischen Typvariabeln mit deklariert
|
||||
@dataclass
|
||||
class NewMyList[T]:
|
||||
|
||||
def __post_init__(self, ):
|
||||
self.__internal_list: list[T] = field(default_factory=list)
|
||||
self.__length: int = 0
|
||||
|
||||
def append(self, value: T):
|
||||
self.__internal_list += [value]
|
||||
self.__length += 1
|
||||
|
||||
def remove(self, value: T):
|
||||
if value in self.__internal_list:
|
||||
self.__internal_list.remove(value)
|
||||
|
||||
def get(self, i: int) -> Optional[T]:
|
||||
if i < len(self):
|
||||
return self[i]
|
||||
return None
|
||||
|
||||
def __len__(self) -> int:
|
||||
return self.__length
|
||||
|
||||
def __getitem__(self, i: int) -> T:
|
||||
return self.__internal_list[i]
|
||||
```
|
68
Notes/src/unterschiede.py
Normal file
68
Notes/src/unterschiede.py
Normal file
@@ -0,0 +1,68 @@
|
||||
from typing import Generic, TypeVar, Optional, Union
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
@dataclass
|
||||
class MyList(Generic[T]):
|
||||
|
||||
def __post_init__(self, ):
|
||||
self.__internal_list: list[T] = field(default_factory=list)
|
||||
self.__length: int = 0
|
||||
|
||||
def append(self, value: T):
|
||||
self.__internal_list += [value]
|
||||
self.__length += 1
|
||||
|
||||
def remove(self, value: T):
|
||||
if value in self.__internal_list:
|
||||
self.__internal_list.remove(value)
|
||||
|
||||
def get(self, i: int) -> Optional[T]:
|
||||
if i < len(self):
|
||||
return self[i]
|
||||
return None
|
||||
|
||||
def __len__(self) -> int:
|
||||
return self.__length
|
||||
|
||||
def __getitem__(self, i: int) -> T:
|
||||
return self.__internal_list[i]
|
||||
|
||||
@dataclass
|
||||
class MyListNew[T]:
|
||||
|
||||
def __post_init__(self, ):
|
||||
self.__internal_list: list[T] = field(default_factory=list)
|
||||
self.__length: int = 0
|
||||
|
||||
def append(self, value: T):
|
||||
self.__internal_list += [value]
|
||||
self.__length += 1
|
||||
|
||||
def remove(self, value: T):
|
||||
if value in self.__internal_list:
|
||||
self.__internal_list.remove(value)
|
||||
|
||||
def get(self, i: int) -> Optional[T]:
|
||||
if i < len(self):
|
||||
return self[i]
|
||||
return None
|
||||
|
||||
def __len__(self) -> int:
|
||||
return self.__length
|
||||
|
||||
def __getitem__(self, i: int) -> T:
|
||||
return self.__internal_list[i]
|
||||
|
||||
|
||||
RealNumber = Union[int, float]
|
||||
|
||||
def add(x: RealNumber, y: RealNumber) -> RealNumber:
|
||||
return x + y
|
||||
|
||||
type NewRealNumber = int | float
|
||||
|
||||
# sonst sieht alles gleich aus
|
||||
def new_add(x: NewRealNumber, y: NewRealNumber) -> NewRealNumber:
|
||||
return x + y
|
@@ -1,8 +1,8 @@
|
||||
# EidP-2024
|
||||
# EidP-2023
|
||||
|
||||
Repository zum Tutorium für EidP für das Wintersemester 2024
|
||||
|
||||
## Kontakt
|
||||
|
||||
* [Mail](mailto:nils@narl.io)
|
||||
* [Discord](https://discord.gg/amykAk3EvC)
|
||||
* [Discord](https://discord.gg/amykAk3EvC)
|
||||
|
@@ -150,4 +150,4 @@ print(app.run('divide', 10, 2))
|
||||
|
||||
---
|
||||
|
||||
# Testing mit `pytest`
|
||||
# Testen mit `pytest`
|
185
Tutorium/tut15/README.md
Normal file
185
Tutorium/tut15/README.md
Normal file
@@ -0,0 +1,185 @@
|
||||
---
|
||||
marp: true
|
||||
paginate: true
|
||||
# class: invert
|
||||
theme: rose-pine
|
||||
footer: Tutorium 15 - 09.02.2024 - Nils Pukropp - https://s.narl.io/s/tutorium-15
|
||||
header:
|
||||
math: mathjax
|
||||
---
|
||||
|
||||
# Tutorium 15 - 19.02.2024
|
||||
|
||||
Orga, Test-Exam, Regex (Exkurs)
|
||||
|
||||
---
|
||||
|
||||
# Orga
|
||||
|
||||
---
|
||||
|
||||
## Orga - Punkte, Vorstellen und einscannen
|
||||
|
||||
- Ich habe bei **allen** auf Blatt 12 (oder dem letzten korrigierten) `+6p` für das **verpasste Tutorium** vergeben
|
||||
- Ich habe für **heute** bereits allen die **Anwesenheitspunkte + Vorstellen** eingetragen
|
||||
|
||||
Alle auf die das Zutrifft sind:
|
||||
|
||||
`as2037, at359, au56, aw616, bo35, cl393, dk446, eh224, eh295, fk439, fv100, ib180, jb1484, jx20, lf409, ln200, lp269, lp321, ls818, mk1518, mr824, mt367, mw793, mz144, mz242, nm320, no43, pk375, rh295, rl173, rw208, sn205, tr211, ua28, vb202, vb205, vr110, yp39, zj11`
|
||||
|
||||
Bei Problemen oder Rückfragen einfach per mail [nils@narl.io](mailto:nils@narl.io) oder nach dem Tutorium
|
||||
|
||||
---
|
||||
|
||||
## Orga - Klausur
|
||||
|
||||
- Klausur am 19.02.
|
||||
- Es gibt vorraussichtlich zwei Termine
|
||||
- 2 Stunden
|
||||
- keine unterschiedlichen Klausuren
|
||||
- Wo, Wann?
|
||||
- individuell
|
||||
- https://courses.laurel.informatik.uni-freiburg.de/courses/2023WS-EiP/exam
|
||||
- https://s.narl.io/s/termin
|
||||
- Klausurumgebung ausprobieren unter
|
||||
- https://bwlehrpool.ruf.uni-freiburg.de/guacamole
|
||||
- https://s.narl.io/s/examvm
|
||||
|
||||
---
|
||||
|
||||
## Orga - Vorbereitung auf Klausur
|
||||
|
||||
- Macht Altklausuren
|
||||
- Übungsaufgaben im Git
|
||||
- https://git.narl.io/nvrl/eidp-klausuraufgaben-2023
|
||||
- https://s.narl.io/s/eidp-ub
|
||||
- Wenn ihr die Probeklausur gut hinbekommen habt (**auch Zeitlich!!!**) seid ihr eig safe
|
||||
- Zusatztutorium mit Dani und mir
|
||||
|
||||
---
|
||||
|
||||
## Orga - Zusatztutorium von Dani und mir
|
||||
|
||||
- Wir machen Altklausuren/Übungsaufgaben
|
||||
- Zu zweit kann man sich etwas persönlicher kümmern
|
||||
- Gibt obv. keine Punkte, wir machen das auch nur freiwillig
|
||||
- Wann, Wo?
|
||||
- Mittwoch
|
||||
- x.xx Uhr open end
|
||||
- Hier in 101
|
||||
- Es folgt auch noch eine E-Mail an alle über dessen Uni-Mail mit allen Infos
|
||||
|
||||
---
|
||||
|
||||
# Test-Exam
|
||||
|
||||
---
|
||||
|
||||
## Test-Exam - Datenklassen
|
||||
|
||||
- Ihr könnt **private** Attribute nicht in einer Unterklasser verwenden!
|
||||
- Mit `super().post_init(...)` könnt ihr diese trotzdem setzen
|
||||
- `self.__privet_attribute` in einer Unterklasse führt zu einem Fehler
|
||||
- Es gibt `protected` welches von Außen nicht sichtbar ist, aber in Unterklassen
|
||||
- `_protected_attribute` welche mit einem `_` annotiert werden
|
||||
- Beißt sich leider etwas mit `InitVar[...]` von `dataclasses`
|
||||
- Vergesst am besten `private`, `public` für die Klausur :) versprechen kann ich aber nichts
|
||||
|
||||
---
|
||||
|
||||
## Test-Exam - Automata
|
||||
|
||||
- Bitte kein `T` oder Trash State in der Klausur, außer es ist explizit gefordert
|
||||
- Ein State bei dem invalide Eingaben hingeschoben werden
|
||||
- Auch wenn das die Musterlösung von Exercise-13 gemacht hat
|
||||
- Und auch wenn es eigentlich sinnvoller ist, weil wir wollen nicht bei einer falschen Eingabe dass unser Programm abstürzt
|
||||
```python
|
||||
class State(Enum):
|
||||
q0 = auto()
|
||||
q1 = auto()
|
||||
q2 = auto()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test-Exam - Automata
|
||||
|
||||
```python
|
||||
def delta(state: State, input: str) -> State:
|
||||
match state, input:
|
||||
case State.q0, "a":
|
||||
return State.q1
|
||||
case State.q0, "b":
|
||||
return State.q2
|
||||
case State.q1, "a":
|
||||
return State.q0
|
||||
case State.q1, "b":
|
||||
return State.q1
|
||||
case State.q2, "a":
|
||||
return State.q2
|
||||
case State.q2, "b":
|
||||
return State.q1
|
||||
case _:
|
||||
raise ValueError("invalid state or input")
|
||||
```
|
||||
---
|
||||
|
||||
# ReGex
|
||||
|
||||
---
|
||||
|
||||
## Was ist ein ReGex?
|
||||
|
||||
- Ein regulärer Ausdruck ist ein **match pattern** in einem **text**
|
||||
- Genau gesagt bildet es eine Menge von Zeichenketten (eine **Sprache**)
|
||||
- Ihr habt bereits ReGex benutzt
|
||||
- Wenn ihr z.B. im Browser Ctrl+F drückt und nach einem Wort sucht
|
||||
- das Wort ist dann ein ReGex
|
||||
- Es gibt aber auch deutlich komplexere ReGex
|
||||
|
||||
---
|
||||
|
||||
## Automaten schon wieder
|
||||
|
||||
- Was ist wenn wir einen Eingabe-String überprüfen wollen ob er
|
||||
- mit `a` beginnt
|
||||
- dann mindest ein, aber beliebig viele `b` folgen
|
||||
- und mit einem `a` endet
|
||||
- Wir können einen Akzeptor zeichnen! (nicht-deterministischen endlichen Automaten mit akzeptierenden Zustand)
|
||||
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## ReGex - Python
|
||||
|
||||
- In Python haben wir `re` also Modul
|
||||
- Ein ReGex ist eine Zeichenkette
|
||||
- `"ab"` akzeptiert `"ab"`
|
||||
- `re.fullmatch(r"ab", "ab")`
|
||||
- Es gibt Sonderzeichen wie `*, +, (, ), ...` mit denen man komplexere Eingaben überprüfen kann
|
||||
- Wir wollen `"ab...a"` von der vorherigen Slide matchen
|
||||
- `b*` möchte 0 bis unendlich `b`
|
||||
- `b+` möchte 1 bis unendlich `b`
|
||||
- also `re.fullmatch(r"ab+a", "abbbbbbba")` ist ein Match
|
||||
|
||||
---
|
||||
|
||||
## Weiter Sonderzeichen/Variabeln
|
||||
|
||||
- Mit `\d` kann man in Python eine beliebige Zahl meinen
|
||||
- Mit `\s` kann man ein beliebigen Whitespace meinen
|
||||
- So kann man z.B. eine beliebige Ip so darstellen
|
||||
- `r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'`
|
||||
- Nützlich zum Parsen oder auch Testen
|
||||
- Ich nutze z.b. ReGex um eure Aufgaben zu testen
|
||||
|
||||
---
|
||||
|
||||
# Viel Erfolg bei der Klausur!
|
||||
|
||||
|
||||
|
BIN
Tutorium/tut15/img/dfa.png
Normal file
BIN
Tutorium/tut15/img/dfa.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
BIN
Tutorium/tut15/slides.pdf
Normal file
BIN
Tutorium/tut15/slides.pdf
Normal file
Binary file not shown.
51
Tutorium/tut15/src/ex5_dataclasses.py
Normal file
51
Tutorium/tut15/src/ex5_dataclasses.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
# (a) Vehicle
|
||||
|
||||
|
||||
@dataclass
|
||||
class Vehicle:
|
||||
seats: int
|
||||
hp: int
|
||||
ccm: int
|
||||
weight: int
|
||||
|
||||
def __post_init__(self):
|
||||
assert 0 < self.seats < 10
|
||||
assert 0 < self.hp
|
||||
assert 0 < self.ccm
|
||||
assert 0 < self.weight
|
||||
|
||||
def fun_factor(self) -> float:
|
||||
return (10 * self.hp + self.ccm) / self.weight
|
||||
|
||||
def __gt__(self, other: 'Vehicle') -> bool:
|
||||
return self.fun_factor() > other.fun_factor()
|
||||
|
||||
# (b) Car
|
||||
|
||||
|
||||
@dataclass
|
||||
class Car(Vehicle):
|
||||
spoiler: bool
|
||||
|
||||
def fun_factor(self) -> float:
|
||||
return super().fun_factor() + (0.2 if self.spoiler else 0)
|
||||
|
||||
|
||||
# (c) Motorcycle
|
||||
|
||||
|
||||
@dataclass
|
||||
class Motorcycle(Vehicle):
|
||||
sidecar: bool
|
||||
|
||||
def __post_init__(self):
|
||||
super().__post_init__()
|
||||
if self.sidecar:
|
||||
assert 2 <= self.seats <= 3
|
||||
else:
|
||||
assert 1 <= self.seats <= 2
|
||||
|
||||
def fun_factor(self) -> float:
|
||||
return super().fun_factor() * (2.4 if self.sidecar else 3)
|
84
Tutorium/tut15/src/ex5_dataclasses_private.py
Normal file
84
Tutorium/tut15/src/ex5_dataclasses_private.py
Normal file
@@ -0,0 +1,84 @@
|
||||
from dataclasses import InitVar, dataclass
|
||||
|
||||
# (a) Vehicle
|
||||
|
||||
|
||||
@dataclass
|
||||
class Vehicle:
|
||||
_seats: InitVar[int]
|
||||
_hp: InitVar[int]
|
||||
_ccm: InitVar[int]
|
||||
_weight: InitVar[int]
|
||||
|
||||
def __post_init__(self, seats: int, hp: int, ccm: int, weight: int):
|
||||
assert 0 < seats < 10
|
||||
assert 0 < hp
|
||||
assert 0 < ccm
|
||||
assert 0 < weight
|
||||
self.__seats = seats
|
||||
self.__hp = hp
|
||||
self.__ccm = ccm
|
||||
self.__weight = weight
|
||||
|
||||
def fun_factor(self) -> float:
|
||||
return (10 * self.__hp + self.__ccm) / self.__weight
|
||||
|
||||
def __gt__(self, other: 'Vehicle') -> bool:
|
||||
return self.fun_factor() > other.fun_factor()
|
||||
|
||||
@property
|
||||
def seats(self) -> int:
|
||||
return self.__seats
|
||||
|
||||
@property
|
||||
def hp(self) -> int:
|
||||
return self.__hp
|
||||
|
||||
@property
|
||||
def ccm(self) -> int:
|
||||
return self.__ccm
|
||||
|
||||
@property
|
||||
def weight(self) -> int:
|
||||
return self.__weight
|
||||
|
||||
# (b) Car
|
||||
|
||||
|
||||
@dataclass
|
||||
class Car(Vehicle):
|
||||
_spoiler: InitVar[bool]
|
||||
|
||||
def __post_init__(self, seats: int, hp: int, ccm: int, weight: int, spoiler: bool):
|
||||
super().__post_init__(seats, hp, ccm, weight)
|
||||
self.__spoiler = spoiler
|
||||
|
||||
def fun_factor(self) -> float:
|
||||
return super().fun_factor() + (0.2 if self.__spoiler else 0)
|
||||
|
||||
@property
|
||||
def has_spoiler(self) -> bool:
|
||||
return self.__spoiler
|
||||
|
||||
|
||||
# (c) Motorcycle
|
||||
|
||||
|
||||
@dataclass
|
||||
class Motorcycle(Vehicle):
|
||||
_sidecar: InitVar[bool]
|
||||
|
||||
def __post_init__(self, seats: int, hp: int, ccm: int, weight: int, sidecar: bool):
|
||||
if sidecar:
|
||||
assert 2 <= seats <= 3
|
||||
else:
|
||||
assert 1 <= seats <= 2
|
||||
super().__post_init__(seats, hp, ccm, weight)
|
||||
self.__sidecar = sidecar
|
||||
|
||||
def fun_factor(self) -> float:
|
||||
return super().fun_factor() * (2.4 if self.__sidecar else 3)
|
||||
|
||||
@property
|
||||
def is_sidecar(self) -> bool:
|
||||
return self.__sidecar
|
Reference in New Issue
Block a user