This commit is contained in:
Nils Pukropp
2024-09-16 21:02:27 +02:00
commit b907cb789e
83 changed files with 5845 additions and 0 deletions

140
Notes/Unterschiede.md Normal file
View 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]
```