Python Lernhandbuch

Kapitel 7: Klassen und Objekte

Musterlösung mit Erklärung

Deine Lösung hat die Prüfung noch nicht bestanden. Lies die Erklärung, dann versuche es erneut – möglichst ohne abzuschreiben.
Aufgabe noch einmal lesen

Schreibe eine Klasse Artikel als Dataclass mit name, preis und bestand (Standard 0). Schreibe dann eine Klasse Lager, die:

  1. intern ein Dictionary Name -> Artikel hält,
  2. hinzufuegen(artikel) anbietet,
  3. entnehmen(name, menge) anbietet und einen ValueError auslöst, wenn der Artikel fehlt oder der Bestand nicht reicht,
  4. die Eigenschaft gesamtwert hat (Summe aus preis * bestand).
python
from dataclasses import dataclass


@dataclass
class Artikel:
    name: str
    preis: float
    bestand: int = 0


class Lager:
    def __init__(self):
        self._artikel = {}

    def hinzufuegen(self, artikel):
        self._artikel[artikel.name] = artikel

    def entnehmen(self, name, menge):
        if name not in self._artikel:
            raise ValueError(f'Unbekannter Artikel: {name}')
        artikel = self._artikel[name]
        if menge > artikel.bestand:
            raise ValueError(f'Nur {artikel.bestand} Stück von {name} vorrätig')
        artikel.bestand -= menge

    @property
    def gesamtwert(self):
        return sum(a.preis * a.bestand for a in self._artikel.values())


lager = Lager()
lager.hinzufuegen(Artikel('Stift', 1.5, 100))
lager.hinzufuegen(Artikel('Heft', 3.0, 40))
lager.entnehmen('Stift', 10)
print(lager.gesamtwert)    # 90 * 1.5 + 40 * 3.0 = 255.0

Was passiert:

  • Artikel braucht als Dataclass keinen eigenen Konstruktor. Artikel('Stift', 1.5, 100) funktioniert sofort.
  • Lager hält die Artikel in self._artikel. Der Unterstrich zeigt: Das ist intern, Benutzer sollen hinzufuegen und entnehmen nutzen.
  • Ein Dictionary mit dem Namen als Schlüssel macht die Suche schnell und einfach (name not in self._artikel).
  • entnehmen prüft zuerst alle Fehlerfälle und ändert den Bestand erst danach. So bleibt das Lager bei einem Fehler unverändert.
  • gesamtwert ist eine @property: Man schreibt lager.gesamtwert ohne Klammern, der Wert wird bei jedem Zugriff frisch berechnet und kann nie veraltet sein.

Warum so: Die Klasse Lager versteckt, wie die Daten gespeichert sind. Du könntest später das Dictionary durch eine Datenbank ersetzen, und der restliche Code müsste sich nicht ändern.