Zum Inhalt springen
Vorschau auf das nächste Semester, noch nicht veröffentlicht.
Zur aktuellen Seite

Keksdose

Sesame Street Quelle: Sesame Street

Aufgabe

So funktioniert die Keksdose

  1. Kapazität: Beim Anlegen legt capacity fest, wie viele Kekse höchstens hineinpassen; ohne Angabe sind es 12. Ist capacity keine positive Ganzzahl (int), etwa 0, -5 oder "ten", gibt es einen ValueError.
  2. Anfangs leer: Eine neue Dose enthält 0 Kekse.
  3. Hineinlegen: deposit(n) legt n Kekse hinein. Würde die Dose dadurch mehr Kekse enthalten, als capacity erlaubt, gibt es einen ValueError.
  4. Herausnehmen: withdraw(n) nimmt n Kekse heraus. Sind weniger als n Kekse in der Dose, gibt es einen ValueError.
  5. Negative Anzahl: Ist n bei deposit oder withdraw negativ, gibt es ebenfalls einen ValueError.
  6. Fehler ändern nichts: Nach einem ValueError enthält die Dose so viele Kekse wie vorher.
  7. Anzeige: str(jar) liefert für jeden Keks in der Dose ein 🍪, bei einer leeren Dose also "".
  8. Abfragen: jar.capacity liefert die Kapazität, jar.size die Zahl der Kekse in der Dose. Beide sind Properties: Man schreibt sie ohne Klammern und kann sie von außen nur lesen.

Beispiel mit einer Dose für 10 Kekse:

AufrufErgebnisjar.sizestr(jar)
jar = Jar(10)neue, leere Dose0""
jar.deposit(8)8🍪🍪🍪🍪🍪🍪🍪🍪
jar.withdraw(3)5🍪🍪🍪🍪🍪
jar.deposit(6)ValueError: 5 + 6 = 11 ist mehr als 105🍪🍪🍪🍪🍪
jar.withdraw(6)ValueError: nur 5 Kekse in der Dose5🍪🍪🍪🍪🍪
jar.deposit(5)Dose ist voll10🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪
Jar(0)ValueError: Kapazität muss positiv sein

Demo

Ein Hauptprogramm brauchen Sie nicht (Sie dürfen aber eines schreiben). Mehr als das hier gibt es also nicht vorzuführen:

Sesame Street Quelle: Sesame Street

Spezifikation

  • Implementieren Sie in jar.py im Ordner jar eine Klasse Jar mit genau diesem Aufbau. Die Parameter der Methoden dürfen Sie nicht ändern; eigene Methoden dürfen Sie ergänzen.

    class Jar:
        def __init__(self, capacity=12):
            ...
    
        def __str__(self):
            ...
    
        def deposit(self, n):
            ...
    
        def withdraw(self, n):
            ...
    
        @property
        def capacity(self):
            ...
    
        @property
        def size(self):
            ...
  • __init__ prüft die Kapazität nach Regel 1 und legt eine leere Dose an (Regel 2).

  • deposit und withdraw ändern die Zahl der Kekse nach den Regeln 3 bis 6.

  • __str__ gibt die Kekse als String zurück (Regel 7).

  • capacity und size geben die Kapazität bzw. die aktuelle Zahl der Kekse zurück (Regel 8).

  • Schreiben Sie in test_jar.py mindestens vier Funktionen, deren Name mit test_ beginnt und die Ihre Klasse zusammen gründlich testen (siehe Testen).

Hilfestellung

Klicken Sie auf die folgenden Tipps, um einige Ratschläge zu erhalten. Versuchen Sie aber zunächst, selbst so weit wie möglich zu kommen.

Ordner und Dateien anlegen

Öffnen Sie VS CodeVisual Studio Code, der kostenlose Code-Editor von Microsoft, in dem Sie im Kurs programmieren. Glossar → entsprechend Ihrem Setup, klicken Sie auf Ihr Terminalfenster und führen Sie cd aus. Die EingabeaufforderungDas Zeichen am Anfang der Zeile im Terminal, etwa $ oder me/ $. Es zeigt, dass das Terminal auf Ihren nächsten Befehl wartet. Steht davor ein Ordnername wie me/, befinden Sie sich gerade in diesem Ordner. Glossar → sollte ungefähr so aussehen:

$

Legen Sie dann den Ordner an, wechseln Sie hinein und öffnen Sie die beiden Dateien:

mkdir jar
cd jar
code jar.py
code test_jar.py
Wo die Zahlen gespeichert werden

Speichern Sie Kapazität und Zahl der Kekse in __init__ in Instanzvariablen mit Unterstrich, etwa self._capacity und self._size. Die Properties capacity und size geben diese Werte dann zurück.

Ohne Unterstrich geht es nicht: self.size = 0 würde versuchen, die Property size zu überschreiben, und Python bricht mit einem AttributeError ab (die Property hat keinen Setter).

Fehler auslösen, Kekse anzeigen

Einen Fehler lösen Sie mit raise aus; der Text in Klammern ist frei wählbar:

if n < 0:
    raise ValueError("Cannot deposit a negative number of cookies.")

Ob ein Wert ein int ist, prüft isinstance(capacity, int).

Den String aus Regel 7 bekommen Sie ohne Schleife: "🍪" * 3 ergibt "🍪🍪🍪".

Gerüst für test_jar.py
import pytest
from jar import Jar


def test_init():
    ...


def test_str():
    jar = Jar()
    assert str(jar) == ""
    jar.deposit(1)
    assert str(jar) == "🍪"
    jar.deposit(11)
    assert str(jar) == "🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪"


def test_deposit():
    ...


def test_withdraw():
    ...

Ob ein Aufruf den erwarteten ValueError auslöst, prüfen Sie mit pytest.raises. Der Test schlägt fehl, wenn im eingerückten Block kein ValueError auftritt:

with pytest.raises(ValueError):
    Jar(-5)

Testen

Schreiben Sie die Tests Schritt für Schritt in test_jar.py und führen Sie nach jedem Schritt

pytest test_jar.py

aus. Jede Funktion legt mit Jar() oder Jar(10) eine eigene Dose an.

TestfunktionWas sie prüft
test_initKapazität einer neuen Dose (Standard 12 und selbst gewählt), size ist 0; ValueError bei ungültiger Kapazität
test_strstr(jar) zeigt nach einigen deposit-Aufrufen die richtige Zahl Kekse
test_depositsize entspricht der Zahl der hineingelegten Kekse; ValueError, wenn die Kapazität überschritten würde
test_withdrawsize stimmt nach dem Herausnehmen; ValueError, wenn mehr Kekse herausgenommen werden sollen, als drin sind

Um withdraw zu testen, müssen erst Kekse in der Dose sein. Rufen Sie dafür im Test einfach vorher deposit auf. Die Aufruffolge aus dem Beispiel eignet sich als Vorlage.

Korrektheit

Führen Sie in Ihrem Terminal den folgenden Befehl aus, um die Korrektheit Ihrer Arbeit zu überprüfen. Testen Sie Ihr Programm aber zuerst selbst.

check50 -l inf-zone/exercises/2026/jar

Style

Führen Sie den folgenden Befehl aus, um den Stil Ihres Codes mit style50Prüfprogramm von CS50, das zeigt, wo Ihr Code von den Formatierungsregeln abweicht. In Grün zeigt es, was Sie ergänzen sollten, in Rot, was wegfallen soll. Glossar → zu analysieren:

style50 jar.py

Abgeben

Geben Sie im Ordner jar ab:

inf upload jar

Danach sehen Sie, welche Tests Ihr Programm besteht und ob die Übung für die Bonuspunkte zählt. Wie Sie inf installieren und sich anmelden, steht unter Abgeben mit inf.

Zum Weiterlesen: Methoden isoliert testen

Für die Lösung der Aufgabe nicht nötig.

Methoden zu testen ist oft aufwendiger als eigenständige Funktionen, weil Methoden den Zustand des Objekts (seine Instanzvariablen) verändern. Um withdraw zu testen, rufen Sie vorher deposit auf. Ist aber deposit fehlerhaft, schlägt womöglich auch der Test von withdraw fehl, obwohl withdraw richtig ist.

Deshalb simulieren Programmierer beim Testen den Zustand oft mit sogenannten Mock-Objekten. Mit Werkzeugen wie Pythons Mock-Objektbibliothek setzen sie den Zustand einer Instanz direkt, ohne eine andere Methode aufzurufen, und testen so jede Methode für sich.

Diese Seite als Markdown: ansehen herunterladen