Files
eidp-2023/Notes/Unterschiede.md
2024-02-06 17:12:47 +01:00

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]