Zwei Werkzeuge machen Klassen im Alltag kürzer und sicherer: Dataclasses nehmen dir Routinecode ab, Properties kontrollieren den Zugriff auf Attribute.
Dataclasses
Für Klassen, die vor allem Daten halten, schreibt man mit @dataclass nur noch die Felder. Python erzeugt __init__, __repr__ und __eq__ selbst:
from dataclasses import dataclass
@dataclass
class Person:
name: str
alter: int
stadt: str = "Köln"
p = Person("Mia", 17)
print(p)
print(p == Person("Mia", 17))
p.alter += 1
print(p.alter)Person(name='Mia', alter=17, stadt='Köln') True 18
Nützliche Optionen
from dataclasses import dataclass, field, asdict, replace
@dataclass(frozen=True, order=True)
class Artikel:
preis: float
name: str = field(compare=False)
tags: tuple = ()
a = Artikel(2.5, "Stift")
b = Artikel(1.0, "Heft")
print(sorted([a, b]))
print(asdict(a))
print(replace(a, preis=9.0))
try:
a.preis = 3
except Exception as e:
print(type(e).__name__)[Artikel(preis=1.0, name='Heft', tags=()), Artikel(preis=2.5, name='Stift', tags=())]
{'preis': 2.5, 'name': 'Stift', 'tags': ()}
Artikel(preis=9.0, name='Stift', tags=())
FrozenInstanceError| Option | Wirkung |
|---|---|
frozen=True | unveränderlich, auch hashbar |
order=True | erzeugt Vergleiche (<, >) über die Felder |
field(default_factory=list) | veränderlicher Standardwert pro Objekt |
field(compare=False) | Feld beim Vergleichen ignorieren |
Properties
Eine Property sieht von außen wie ein Attribut aus, ruft aber Code auf. So prüfst du Werte oder berechnest sie bei Bedarf:
class Temperatur:
def __init__(self, celsius):
self.celsius = celsius # läuft durch den Setter
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, wert):
if wert < -273.15:
raise ValueError("Unter dem absoluten Nullpunkt")
self._celsius = wert
@property
def fahrenheit(self): # nur lesbar, wird berechnet
return self._celsius * 9 / 5 + 32
t = Temperatur(25)
print(t.celsius, t.fahrenheit)
t.celsius = 100
print(t.fahrenheit)
try:
t.celsius = -300
except ValueError as e:
print("Fehler:", e)25 77.0 212.0 Fehler: Unter dem absoluten Nullpunkt
__slots__
Mit __slots__ legst du fest, welche Attribute ein Objekt haben darf. Das spart Speicher und verhindert Tippfehler bei Attributnamen:
class Punkt:
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x, self.y = x, y
p = Punkt(1, 2)
try:
p.z = 3
except AttributeError:
print("kein Attribut z erlaubt")kein Attribut z erlaubt
Merke
@dataclasserzeugt__init__,__repr__,__eq__automatischfrozen=Truemacht unveränderlich,order=Truesortierbar- Veränderliche Standardwerte mit
field(default_factory=...) @propertymacht aus einer Methode ein Attribut,@x.setterprüft Zuweisungen__slots__beschränkt Attribute und spart Speicher
Aufgabe
Schreibe eine Dataclass Buch mit Titel, Autor und Seitenzahl. Ergänze eine Property dick, die True liefert, wenn das Buch mehr als 500 Seiten hat.