4.0 KiB
4.0 KiB
Unterschiede zu Vorjahren
Typalias
Manchmal braucht man eine Kombination aus Datentypen
Vorher
Erstellen von Typaliasen mit Union
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
# `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
:
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
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]