Getränkeautomat - Hilfe benötigt

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
Albo
User
Beiträge: 3
Registriert: Mittwoch 28. April 2021, 12:10

Hallo Forum-Mitglieder,

ich heiße Miko und bin neu hier. Ich habe erst vor kurzer Zeit mit dem Programmieren begonnen.
In meinem Kurs beschäftige ich mich gerade mit der Aufgabe eines Getränkeautomaten zu erstellen.

Ich habe mich hier etwas "festgefahren". :oops:

Die Aufgabenstellung ist Folgende:
1. Aufgabe:
Erstellen Sie eine Klasse für Getränke. Die Klasse soll den Namen des Getränks, den Preis pro Flasche und die noch vorhandene Anzahl Flaschen speichern können.
Ersetzen Sie dann in dem Getränkeautomaten aus diesem Studienheft die Attribute für die Getränke durch Instanzen der Klasse für die Getränke. Achten Sie dabei bitte auf die Datenkapselung.
Benutzen Sie für die Lösung mit den Methoden _init_() und _del_().
2. Aufgabe:
Erstellen Sie den Getränkeautomaten so, dass vor der Berechnung des Gesamtpreises geprüft wird, ob noch genügend Flaschen des gewünschten Getränks vorhanden sind. Wenn nicht, muss der Gesamtpreis aus der noch maximal verfügbaren Anzahl Flaschen berechnet werden. Es soll auch keine Rückgabe des eventuell zu viel gezahlten Geldes erfolgen.



Ich würde mich sehr freuen :D , wenn mir jemand etwas dazu sagen kann.
Hier ist mein code und anschließend die Fehlermeldung.


"""************************************************
Vorlage: Der Getränkeautomat Version 6
Lösung der Aufgabe 1 und Aufgabe 2
************************************************"""


# die Vereinbarung der Klasse für die Getränkeeinheit
class Getraenkeeinheit:
# die Methode __init__()
def __init__(self, temp_name, temp_preis, temp_anzahl):

# eine leere Liste für die Getränkenamen
self.getraenke_name = []
# die Getränke eintragen
self.getraenke_name.append("Limonade")
self.getraenke_name.append("Wasser")
self.getraenke_name.append("Bier")
self.name = temp_name
self.name = name

# eine leere Liste für die Getränkepreise
self.getraenke_preis = []
# den Preis eintragen
self.getraenke_preis.append(10)
self.getraenke_preis.append(20)
self.getraenke_preis.append(30)
self.preis = temp_preis
# Preis pro Flasche
self.preis = preis

# eine leere Liste für die Getränkeanzahl
self.getraenke_anzahl = []
# die Anzahl eintragen
self.getraenke_anzahl.append(10)
self.getraenke_anzahl.append(15)
self.getraenke_anzahl.append(20)
self.anzahl = temp_anzahl
self.anzahl = anzahl

# Liste für die restlichen Flaschen
self.rest = []

# die Methode __del__()
def __del__(self):
print("Eine Instanz der Klasse Getränkeeinheit wurde gelöscht")

def get_namen(self):
return self.name

# Methode, die den Rest an die Klasse "Getränkeeinheit" übergibt
def rest_flaschen(self, rest, name):
self.rest.append(rest)
# Ausgabe wie viele Flaschen noch vorhanden sind
print("Es sind noch", self.rest, "Flaschen(n)", name, "enthalten.")


# die Vereinbarung der Klasse für die Münzeinheit
class Muenzeinheit:
# die Methode __init__()
def __init__(self):
# die Attribute
self.betrag = 0
self.noch_zu_zahlen = 0
self.rueckgeld = 0

# die Methode __del__()
def __del__(self):
print("Eine Instanz der Klasse Muenzeinheit wurde gelöscht.")

# die weiteren Methoden
def muenzen_annehmen(self, wert):
self.noch_zu_zahlen = self.noch_zu_zahlen - wert

def rueckgeld_geben(self):
# den absoluten Betrag von noch_zu_zahlen als Rückgeld liefern
self.rueckgeld = abs(self.noch_zu_zahlen)
return self.rueckgeld

def set_betrag(self, preis):
self.betrag = preis
self.noch_zu_zahlen = self.betrag

def get_noch_zu_zahlen(self):
return self.noch_zu_zahlen


# die Vereinbarung der Klasse für den Getränkeautomat
class Getraenkeautomat:
# übergeben werden die Anzahl und eine Referenz auf die Münzeinheit
# die Methode __init__()
def __init__(self, temp_zahlomat, temp_trankomat):
# die Attribute
# jetzt ist die Münzeinheit Teil des Automaten
self.zahlomat = temp_zahlomat
# jetzt ist die Getränkeeinheit Teil des Automaten
self.trankomat = temp_trankomat

self.name = self.trankomat.get_namen()
self.preis = self.trankomat.get_preis()

# eine leere liste für die Anzahl der Flaschen
self.anzahl_flaschen = self.trankomat.get_anzahl_flaschen()

# die Anzahl der Flaschen
# sie werden jetzt durch die Argumente gesetzt
self.anzahl_flaschen.append(anzahl1)
self.anzahl_flaschen.append(anzahl2)
self.anzahl_flaschen.append(anzahl3)

# die Kühlung ist aus
self.kuehlung = False

# die Methode __del__()
def __del__(self):
print("Eine Instanz der Klasse Getraenkeautomat wurde gelöscht.")

# Auswahl der Getränke durch Abfrage des Anwenders
def getraenk_waehlen(self):
print("Bitte wählen Sie ein Getränk!")
print("Es gibt folgende Auswahl:")
anzeige_auswahl = 1
# Anzeige der Getränkeliste
for getraenk in self.trankomat.getraenke_name:
print(anzeige_auswahl, getraenk)
anzeige_auswahl = anzeige_auswahl + 1

# Auswahl
auswahl = int(input("Geben Sie die gewünschte Nummer ein: "))

# gibt es noch Flaschen vom gewählten Getränk?
if int(self.anzahl_flaschen[auswahl-1]) != 0:
auswahl = auswahl - 1
# die Anzahl der Flaschen einlesen
anzahl = int(input("Wie viele Flaschen möchten Sie? "))

# überprüfen ob genug Flaschen vorhanden sind
# die Anzahl der Flaschen wird auf die noch vorhandene Anzahl der Flaschen geändert
if anzahl > self.anzahl_flaschen[auswahl]:
anzahl = self.anzahl_flaschen[auswahl]

# erst muss bezahlt werden - Der Preis wird mit der Anzahl der gewählten Flaschen berechnet
# der Preis 10 ist fest vorgegeben
print("Sie müssen", anzahl * self.trankomat.preis, "Cent bezahlen.")
self.zahlomat.set_betrag(anzahl * self.trankomat.preis)
while self.zahlomat.get_noch_zu_zahlen() > 0:
print("Es fehlen noch", self.zahlomat.get_noch_zu_zahlen(), "Cent.")
self.zahlomat.muenzen_annehmen(3)

# das Getraenk ausgeben
self.getraenk_ausgeben(anzahl, auswahl)
else:
print("Das gewählte Getränk ist leider nicht mehr vorhanden.")
auswahl = -1

return auswahl

def getraenk_ausgeben(self, anzahl, getraenke_index):
# gibt es noch genügend Flaschen?
if anzahl <= self.anzahl_flaschen[getraenke_index]:
print("Sie erhalten", anzahl, "Flasche(n)", self.trankomat.getraenke_name[getraenke_index])
self.anzahl_flaschen[getraenke_index] = self.anzahl_flaschen[getraenke_index] - anzahl
else:
print("Es sind nur noch", self.anzahl_flaschen[getraenke_index], "Flaschen", self.trankomat.getraenke_name[getraenke_index], "vorhanden.")
print("Sie erhalten", anzahl, "Flaschen(n).")
self.anzahl_flaschen[getraenke_index] = 0
# Geld zurückgeben
print("Sie erhalten", self.zahlomat.rueckgeld_geben(), "Cent zurück.")
# aufrufen der Methode für die Übergabe restlichen Flaschen
# die Werte für die verbleibenden Flaschen nach der Ausgabe und der Name werden übergeben
self.trankomat.rest_flaschen(self.anzahl_flaschen[getraenke_index], self.trankomat.getraenke_name[getraenke_index])

def kuehlen(self, an_aus):
self.kuehlung = an_aus
if self.kuehlung == True:
print("Die Kühlung ist eingeschaltet.")
else:
print("Die Kühlung ist ausgeschaltet.")

# eine Getränkeeinheit erzeugen und Attribute übergeben
flasche = Getraenkeeinheit(getraenke_name, getraenke_preis, getraenke_anzahl)

# eine Münzeinheit erzeugen
einheit = Muenzeinheit()

# einen Automaten erzeugen
# die Münzeinheit und die Anzahl der Getränke übergeben
automat = Getraenkeautomat(einheit, flasche)

auswahl = -1
# die Kühlung einschalten
automat.kuehlen(True)

# ein Getränk auswählen
while auswahl == -1:
auswahl = automat.getraenk_waehlen()

# die Kühlung ausschalten
automat.kuehlen(False)

# die Instanzen ausdrücklich freigeben
# zuerst den Automaten
del automat
# die Getränkeeinheit
del flasche
# die Münzeinheit
del einheit



Fehlermeldung:
Traceback (most recent call last):
File "D:\06. Weiterbildung - Kurse\Der Getränkeautomat - NEU.py", line 181, in <module>
flasche = Getraenkeeinheit(getraenke_name, getraenke_preis, getraenke_anzahl)
NameError: name 'getraenke_name' is not defined

Process finished with exit code 1
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Bitte hier im Forum code-Tags (</>) benutzen, damit der Code auch lesbar ist.
Benutze kein __del__, das ist selten sinnvoll, und mit den speziellen Fällen, wo man es wirklich braucht, kommt man als Anfänger nie in Berührung.

Dann dachte ich, es geht im Getränke, und nicht um Temperaturen, warum also temp_name, temp_preis und temp_anzahl?
Eine Getraenkeeinheit soll doch ein Getränk repräsentieren. Was sollen dann die Listen, in denen fest codierte Namen, Preise und Anzahlen stehen?
`name`, `preis` und `anzahl` sind in Getraenkeeinheit.__init__ nirgends definiert.
Die Methode get_namen ist überflüssig, da Du auch an den entsprechenden Stellen direkt auf xy.name zugreifen kannst.
Ebenso ist Muenzeinheit.get_noch_zu_zahlen überflüssig.

Die Methode Muenzeinheit.rueckgeld_geben ist falsch, da sie auch positive noch_zu_zahlen-Beträge als Rückgeld ausgibt.

In Getraenkeautomat.__init__ gibt es wieder Variablen, die auf die Temperatur hindeuten, aber ein Zahlomat muß bestimmt nicht gekült werden?
Es gibt kein get_anzahl_flaschen und auch keine anzahl1, anzahl2 und anzahl3. self.name und self.preis werden nirgends verwendet, was auch gut so ist, self.anzahl_flaschen sollte auch nicht verwendet werden.
Solangsam kapiere ich die Struktur. `Getraenkeeinheit` soll gar kein einzelnen Getränk sein, sondern eine Menge an Getränken. Dann fehlt also noch die Klasse für ein einzelnes Getränk komplett.

In getraenk_waehlen: wenn Du einen Zähler brauchst, benutzt enumerate.
Der Gesamtbetrag sollte nur einmal im Code berechnet werden.
Die kryptische -1 für einen Fehler sollte es nicht geben. Entweder bentuzt man None, oder erzeugt gleich eine Exception im Fehlerfall.

Das Hauptprogramm gehört in eine Funktion, die man üblicherweise `main` nennt.
Ja, die Fehlermeldung stimmt, getraenke_name, getraenke_preis und getraenke_anzahl sind nicht definiert. Bevor man Variablen benutzen kann, muß man sie definieren.
Variablen definiert man dann, wenn man sie braucht. Das auswahl = -1 ist viel zu weit von der while-Schleife entfernt. Wenn eine while-Schleife nur startet, wenn man eine Variable mit dummy-Wert belegt, dann ist das eigentlich eine while-True-Schleife, die an passender Stelle per if und break verlassen wird.

Lösche sofort die Zeilen mit `del`. In dieser Form wird `del` nie gebraucht. Dein Lehrer hat eine falsche Vorstellung vom Speichermanagement von Python. Falls er näheres Wissen will, verweise ihn gerne an dieses Forum.

Zusammengefasst:
Dein Code enthält viele Stellen, die so nicht funktionieren und auch keinen Sinn ergeben.
Schreibe nur Code, der auch funktioniert, das heißt, bevor Du eine Funktion benutzt, schreibe diese Funktion und teste sie ausführlich. Überlege Dir, was die Funktion wirklich tun soll, was sie an Parametern braucht, und benenne sie aussagekräftig. Anhängsel wie temp sind absolut überflüssig, weil sie keinen Mehrwert bieten.
Plane Dein Programm von oben nach unten, fange aber dann mit dem Code-Schreiben unten an, damit Du ihn gleich testen kannst.
Hier bei Deinem Beispiel: ein Getränkeautomat besteht aus einer Getränkeeinheit und einer Münzeinheit, und eine Getränkeeinheit besteht aus mehreren Getränken.
Dann fängst Du damit an, die Getränke-Klasse zu schreiben.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ergänzend: Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.

Was wirklich total sinnlos ist, ist zu vor Klassen und Methoden zu kommentieren welche Klasse und welche Methode da in der nächsten Zeile definiert wird.

Dann möchte ich noch mal bekräftigen das die `__del__()`-Methoden da verschwinden müssen. Die sind falsch. Und was die Speicherverwaltung angeht sogar nicht ganz ungefährlich, weil die blosse Existenz so einer Methoden unter bestimmten Umständen sogar dazu führen kann, dass die Objekte *nicht* von der Speicherverwaltung abgeräumt werden, auch wenn sie gar nicht mehr benötigt werden.

Der Kommentare mit dem „ausdrücklich freigeben“ bei den ``del``-Anweisungen ist falsch: ``del`` löscht keine Objekte sondern Namen. Das *kann* dazu führen, dass in der Folge auch der Speicher von Objekten freigegeben wird, muss es aber nicht. Und es gibt auch keine Garantie *wann* das passiert, wenn es passiert. ``del`` ist kein Mittel zur Speicherverwaltung und auf reinen Namen braucht man das nur ganz selten.

Der automatischen Speicherverwaltung greift man dadurch unter die Arme das man sinnvolle Funktionen schreibt, wo dann nach Funktionsende die lokalen Namen automatisch verschwinden und Objekte die nicht mehr erreichbar sind, dadurch zur Freigabe freigegeben sind. Da muss man keinen extra Code schreiben der versucht etwas zu machen was in Python so schlicht nicht möglich ist.

Die Getränkeeinheit `flasche` zu nennen ist sehr irreführend weil etwas das Flaschen verwaltet selbst ja keine Flasche ist.

Und wenn es eine Getränkeeinheit und eine Münzeinheit im gleichen Namensraum gibt, kann man eines davon nicht einfach nur `einheit` nennen, weil das ja total willkürlich wäre ob man den Namen nun für die Getränkeeinheit oder für die Münzeinheit wählt, und für die andere muss man sich dann einen Namen ausdenken der ”asymmetrisch” ist.

Der Rückgabwert von `getraenk_waehlen()` wird nirgends verwendet. Ich sehe auch nicht wozu der gut sein sollte.

Benutzereingaben werden nicht überprüft, weder ob der Benutzer überhaupt eine Zahl eingibt, noch ob die in einem sinnvollen Wertebereich liegt. Sowohl bei der Getränkeauswahl als auch bei der Anzahl machen beispielsweise negative Zahlen keinen Sinn. Benutzer können die aber eingeben.

Der Kommentar, dass der Preis 10 fest vorgegeben ist, stimmt bei dieser Teilaufgabe offensichtlich nicht mehr, denn der Preis soll hier ja pro Getränk festgelegt werden können.

Laut Aufgabenstellung soll *keine* Rückgeldausgabe erfolgen, der Teil kann also raus.

Das ganze läuft dann in etwa auf so etwas hinaus:

Code: Alles auswählen

#!/usr/bin/env python3
"""
Vorlage: Der Getränkeautomat Version 6
Lösung der Aufgabe 1 und Aufgabe 2
"""
from attr import attrib, attrs


@attrs
class Getraenk:
    name = attrib()
    preis = attrib()
    anzahl = attrib()


@attrs
class Getraenkeeinheit:
    getraenke = attrib()


@attrs
class Muenzeinheit:
    offener_betrag = attrib(default=0)

    def muenzen_annehmen(self, wert):
        self.offener_betrag -= wert


@attrs
class Getraenkeautomat:
    trankomat = attrib()
    zahlomat = attrib()
    ist_kuehlung_an = attrib(default=False)

    def kuehlung_schalten(self, status):
        self.ist_kuehlung_an = status
        print(
            "Die Kühlung ist {}geschaltet.".format(
                "ein" if self.ist_kuehlung_an else "aus"
            )
        )

    def getraenk_waehlen(self):
        print("Bitte wählen Sie ein Getränk!\nEs gibt folgende Auswahl:")
        for nummer, getraenk in enumerate(self.trankomat.getraenke, 1):
            print(
                f"{nummer:2d}. {getraenk.name} ({getraenk.anzahl})"
                f" - {getraenk.preis} ¢ / Flasche)"
            )
        #
        # FIXME Fehlerbehandlung wenn der Benutzer keine Zahl eingibt.
        #
        auswahl = int(input("Geben Sie die gewünschte Nummer ein: "))
        #
        # FIXME Wertebereich der Eingabe prüfen.
        #
        getraenk = self.trankomat.getraenke[auswahl - 1]
        if getraenk.anzahl > 0:
            #
            # FIXME Fehlerbehandlung wenn der Benutzer keine Zahl eingibt.
            # FIXME Wertebereich sinnvoll einschränken.
            #
            anzahl = min(
                int(input("Wie viele Flaschen möchten Sie? ")), getraenk.anzahl
            )
            preis = anzahl * getraenk.preis
            print("Sie müssen", preis, "Cent bezahlen.")
            assert self.zahlomat.offener_betrag <= 0
            self.zahlomat.offener_betrag = preis
            while self.zahlomat.offener_betrag > 0:
                print(
                    "Es fehlen noch",
                    self.zahlomat.offener_betrag,
                    "Cent.",
                )
                self.zahlomat.muenzen_annehmen(3)

            print(
                "Sie erhalten {} Flasche{} {}.".format(
                    anzahl, "" if anzahl == 1 else "n", getraenk.name
                )
            )
            getraenk.anzahl -= anzahl
        else:
            print("Das gewählte Getränk ist leider nicht mehr vorhanden.")


def main():
    automat = Getraenkeautomat(
        Getraenkeeinheit(
            [
                Getraenk("Limonade", 10, 10),
                Getraenk("Wasser", 20, 15),
                Getraenk("Bier", 30, 20),
            ]
        ),
        Muenzeinheit(),
    )
    automat.kuehlung_schalten(True)
    while True:
        automat.getraenk_waehlen()
    automat.kuehlung_schalten(False)


if __name__ == "__main__":
    main()
Wobei man hier natürlich denn Sinn der `*omat`-Werte hinterfragen kann und/oder die Aufteilung der Funktionalität zwischen den Klassen.

Was auch unschön ist, ist die Vermischung zwischen Programmlogik und Benutzerinteraktion. Im aktuellen Zustand kann man beispielsweise die Kommunikation per Konsole nicht einfach durch eine GUI ersetzen oder erweitern, ohne Teile der Logik zu kopieren/noch mal nachzuprogrammieren.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Albo
User
Beiträge: 3
Registriert: Mittwoch 28. April 2021, 12:10

recht herzlichen Dank für eure Kommentare. Das ist alles sehr hilfreich für mich.
ich werde mir über alle Tipps Gedanken machen und die Sache nochmal neu angehen.
... nicht versetzt!

Anmerkung zu den Methoden mit __del__()
Laut meiner Aufgabenstellung soll ich den Beispielcode im Studienheft als Vorlage benutzen:
Die Klasse soll den Namen des Getränks, den Preis pro Flasche und die noch vorhandene Anzahl Flaschen speichern können.
Ersetze dann in dem Getränkeautomaten aus diesem Studienheft die Attribute für die Getränke durch Instanzen der Klasse für die Getränke. Achte dabei bitte auf die Datenkapselung.
Unser Getränkeautomat ist ein „Betrüger“. Der Preis für die Flaschen wird berechnet, bevor geprüft wird, ob noch genügend Flaschen vorhanden sind. Es erfolgt auch keine Rückgabe des eventuell zu viel gezahlten Geldes.
Ändere den Getränkeautomaten so, dass vor der Berechnung des Gesamtpreises geprüft wird, ob noch genügend Flaschen des gewünschten Getränks vorhanden sind. Wenn nicht, muss der Gesamtpreis aus der noch maximal verfügbaren Anzahl Flaschen berechnet werden
Die Vorlage für die Lösung der beiden Aufgaben ist der folgende Code:

Code: Alles auswählen

""" ************************************************
Der Getränkeautomat Version 6
mit __init__() und __del__()
************************************************"""


# die Vereinbarung der Klasse für die Münzeinheit
class Muenzeinheit:
    # die Methode __init__()
    def __init__(self):
        # die Attribute
        self.betrag = 0
        self.noch_zu_zahlen = 0
        self.rueckgeld = 0

    # die Methode __del__()
    def __del__(self):
        print("Eine Instanz der Klasse Muenzeinheit wurde gelöscht.")

    # die weiteren Methoden
    def muenzen_annehmen(self, wert):
        self.noch_zu_zahlen = self.noch_zu_zahlen - wert

    def rueckgeld_geben(self):
        # den absoluten Betrag von noch_zu_zahlen als Rückgeld liefern
        self.rueckgeld = abs(self.noch_zu_zahlen)
        return self.rueckgeld

    def set_betrag(self, preis):
        self.betrag = preis
        self.noch_zu_zahlen = self.betrag

    def get_noch_zu_zahlen(self):
        return self.noch_zu_zahlen


# die Vereinbarung der Klasse für den Automaten
class Getraenkeautomat:
    # übergeben werden die Anzahl und eine Referenz auf die Münzeinheit
    def __init__(self, anzahl1, anzahl2, anzahl3, temp_zahlomat):
        # die Attribute
        # jetzt ist die Münzeinheit Teil des Automaten
        self.zahlomat = temp_zahlomat

        # eine leere Liste für die Getränkenamen  
        self.getraenk = []
        # eine leere Liste für die Anzahl der Flaschen
        self.anzahl_flaschen = []

        # die Getränke eintragen
        self.getraenk.append("Limonade")
        self.getraenk.append("Wasser")
        self.getraenk.append("Bier")

        # die Anzahl der Flaschen
        # Sie werden jetzt durch die Argumente gesetzt
        self.anzahl_flaschen.append(anzahl1)
        self.anzahl_flaschen.append(anzahl2)
        self.anzahl_flaschen.append(anzahl3)

        # die Kühlung ist aus
        self.kuehlung = False

    def __del__(self):
        print("Eine Instanz der Klasse Getraenkeautomat wurde gelöscht.")

    def getraenke_waehlen(self):
        # die Auswahl
        print("Bitte wählen Sie ein Getränk:")
        print("Es gibt folgende Auswahl:")
        anzeige_auswahl = 1
        for getraenk in self.getraenk:
            print(anzeige_auswahl, getraenk)
            anzeige_auswahl = anzeige_auswahl + 1

        auswahl = int(input("Geben Sie die gewünschte Nummer ein: "))

        # gibt es noch Flaschen vom gewählten Getränk?
        if self.anzahl_flaschen[auswahl - 1] != 0:
            # die Anzahl der Flaschen einlesen
            anzahl = int(input("Wie viele Flaschen möchten Sie? "))

            # erst muss bezahlt werden
            # der Preis 10 ist fest vorgegeben
            print("Sie müssen", anzahl * 10, "Cent bezahlen.")
            self.zahlomat.set_betrag(anzahl * 10)
            while self.zahlomat.get_noch_zu_zahlen() > 0:
                print("Es fehlen noch", self.zahlomat.get_noch_zu_zahlen(), "Cent.")
                self.zahlomat.muenzen_annehmen(3)

            # das Getränk ausgeben
            auswahl = auswahl - 1
            self.getraenk_ausgeben(anzahl, auswahl)
        else:
            print("Das gewählte Getränk ist leider nicht mehr vorhanden.")
            auswahl = -1

        return auswahl

    def getraenk_ausgeben(self, anzahl, getraenke_index):
        # gibt es noch genügend Flaschen?
        if anzahl <= self.anzahl_flaschen[getraenke_index]:
            print("Sie erhalten", anzahl, "Flasche(n)", self.getraenk[getraenke_index])
            self.anzahl_flaschen[getraenke_index] = self.anzahl_flaschen[getraenke_index] - anzahl
        else:
            print("Es sind nur noch", self.anzahl_flaschen[getraenke_index], "Flaschen", self.getraenk[getraenke_index],
                  "vorhanden.")
            print("Sie erhalten den Rest.")
            self.anzahl_flaschen[getraenke_index] = 0
        # Geld zurückgeben
        print("Sie erhalten", self.zahlomat.rueckgeld_geben(), "Cent zurück.")

    def kuehlen(self, an_aus):
        self.kuehlung = an_aus
        if self.kuehlung == True:
            print("Die Kühlung ist eingeschaltet.")
        else:
            print("Die Kühlung ist ausgeschaltet.")

        # eine Münzeinheit erzeugen


einheit = Muenzeinheit()
# einen Automaten erzeugen
# die Münzeinheit und die Anzahl der Getränke werden übergeben
automat = Getraenkeautomat(10, 20, 30, einheit)

auswahl = -1
# die Kühlung einschalten
automat.kuehlen(True)

# ein Getränk auswählen
while auswahl == -1:
    auswahl = automat.getraenke_waehlen()

# die Kühlung ausschalten
automat.kuehlen(False)

# die Instanzen ausdrücklich freigeben
# zuerst den Automaten
del automat
# und die Münzeinheit
del einheit

Das war mein Pfusch!!

Code: Alles auswählen

""" Miko 4-1 ************************************************
Vorlage: Der Getränkeautomat Version 6
Lösung der Aufgabe 1 und Aufgabe 2
************************************************"""


# die Vereinbarung der Klasse für die Getränkeeinheit
class Getraenkeeinheit:
    # die Methode __init__()
    def __init__(self, temp_name, temp_preis, temp_anzahl):
        
        # eine leere Liste für die Getränkenamen
        self.getraenke_name = []
        # die Getränke eintragen
        self.getraenke_name.append("Limonade")
        self.getraenke_name.append("Wasser")
        self.getraenke_name.append("Bier")
        self.name = temp_name
        self.name = name

        # eine leere Liste für die Getränkepreise
        self.getraenke_preis = []
        # den Preis eintragen
        self.getraenke_preis.append(10)
        self.getraenke_preis.append(20)
        self.getraenke_preis.append(30)
        self.preis = temp_preis
        # Preis pro Flasche
        self.preis = preis

        # eine leere Liste für die Getränkeanzahl
        self.getraenke_anzahl = []
        # die Anzahl eintragen
        self.getraenke_anzahl.append(10)
        self.getraenke_anzahl.append(15)
        self.getraenke_anzahl.append(20)
        self.anzahl = temp_anzahl
        self.anzahl = anzahl

        # Liste für die restlichen Flaschen
        self.rest = []

    # die Methode __del__()
    def __del__(self):
        print("Eine Instanz der Klasse Getränkeeinheit wurde gelöscht")

    def get_namen(self):
        return self.name

    # Methode, die den Rest an die Klasse "Getränkeeinheit" übergibt
    def rest_flaschen(self, rest, name):
        self.rest.append(rest)
        # Ausgabe wie viele Flaschen noch vorhanden sind
        print("Es sind noch", self.rest, "Flaschen(n)", name, "enthalten.")


# die Vereinbarung der Klasse für die Münzeinheit
class Muenzeinheit:
    # die Methode __init__()
    def __init__(self):
        # die Attribute
        self.betrag = 0
        self.noch_zu_zahlen = 0
        self.rueckgeld = 0

    # die Methode __del__()
    def __del__(self):
        print("Eine Instanz der Klasse Muenzeinheit wurde gelöscht.")

    # die weiteren Methoden
    def muenzen_annehmen(self, wert):
        self.noch_zu_zahlen = self.noch_zu_zahlen - wert

    def rueckgeld_geben(self):
        # den absoluten Betrag von noch_zu_zahlen als Rückgeld liefern
        self.rueckgeld = abs(self.noch_zu_zahlen)
        return self.rueckgeld

    def set_betrag(self, preis):
        self.betrag = preis
        self.noch_zu_zahlen = self.betrag

    def get_noch_zu_zahlen(self):
        return self.noch_zu_zahlen


# die Vereinbarung der Klasse für den Getränkeautomat
class Getraenkeautomat:
    # übergeben werden die Anzahl und eine Referenz auf die Münzeinheit
    # die Methode __init__()
    def __init__(self, temp_zahlomat, temp_trankomat):
        # die Attribute
        # jetzt ist die Münzeinheit Teil des Automaten
        self.zahlomat = temp_zahlomat
        # jetzt ist die Getränkeeinheit Teil des Automaten
        self.trankomat = temp_trankomat

        self.name = self.trankomat.get_namen()
        self.preis = self.trankomat.get_preis()

        # eine leere liste für die Anzahl der Flaschen
        self.anzahl_flaschen = self.trankomat.get_anzahl_flaschen()

        # die Anzahl der Flaschen
        # sie werden jetzt durch die Argumente gesetzt
        self.anzahl_flaschen.append(anzahl1)
        self.anzahl_flaschen.append(anzahl2)
        self.anzahl_flaschen.append(anzahl3)

        # die Kühlung ist aus
        self.kuehlung = False

    # die Methode __del__()
    def __del__(self):
        print("Eine Instanz der Klasse Getraenkeautomat wurde gelöscht.")

    # Auswahl der Getränke durch Abfrage des Anwenders
    def getraenk_waehlen(self):
        print("Bitte wählen Sie ein Getränk!")
        print("Es gibt folgende Auswahl:")
        anzeige_auswahl = 1
        # Anzeige der Getränkeliste
        for getraenk in self.trankomat.getraenke_name:
            print(anzeige_auswahl, getraenk)
            anzeige_auswahl = anzeige_auswahl + 1

        # Auswahl
        auswahl = int(input("Geben Sie die gewünschte Nummer ein: "))

        # gibt es noch Flaschen vom gewählten Getränk?
        if int(self.anzahl_flaschen[auswahl-1]) != 0:
            auswahl = auswahl - 1
            # die Anzahl der Flaschen einlesen
            anzahl = int(input("Wie viele Flaschen möchten Sie? "))

            # überprüfen ob genug Flaschen vorhanden sind
            # die Anzahl der Flaschen wird auf die noch vorhandene Anzahl der Flaschen geändert
            if anzahl > self.anzahl_flaschen[auswahl]:
                anzahl = self.anzahl_flaschen[auswahl]

            # erst muss bezahlt werden - Der Preis wird mit der Anzahl der gewählten Flaschen berechnet
            # der Preis 10 ist fest vorgegeben
            print("Sie müssen", anzahl * self.trankomat.preis, "Cent bezahlen.")
            self.zahlomat.set_betrag(anzahl * self.trankomat.preis)
            while self.zahlomat.get_noch_zu_zahlen() > 0:
                print("Es fehlen noch", self.zahlomat.get_noch_zu_zahlen(), "Cent.")
                self.zahlomat.muenzen_annehmen(3)

            # das Getraenk ausgeben
            self.getraenk_ausgeben(anzahl, auswahl)
        else:
            print("Das gewählte Getränk ist leider nicht mehr vorhanden.")
            auswahl = -1

        return auswahl

    def getraenk_ausgeben(self, anzahl, getraenke_index):
        # gibt es noch genügend Flaschen?
        if anzahl <= self.anzahl_flaschen[getraenke_index]:
            print("Sie erhalten", anzahl, "Flasche(n)", self.trankomat.getraenke_name[getraenke_index])
            self.anzahl_flaschen[getraenke_index] = self.anzahl_flaschen[getraenke_index] - anzahl
        else:
            print("Es sind nur noch", self.anzahl_flaschen[getraenke_index], "Flaschen", self.trankomat.getraenke_name[getraenke_index], "vorhanden.")
            print("Sie erhalten", anzahl, "Flaschen(n).")
            self.anzahl_flaschen[getraenke_index] = 0
        # Geld zurückgeben
        print("Sie erhalten", self.zahlomat.rueckgeld_geben(), "Cent zurück.")
        # aufrufen der Methode für die Übergabe restlichen Flaschen
        # die Werte für die verbleibenden Flaschen nach der Ausgabe und der Name werden übergeben
        self.trankomat.rest_flaschen(self.anzahl_flaschen[getraenke_index], self.trankomat.getraenke_name[getraenke_index])

    def kuehlen(self, an_aus):
        self.kuehlung = an_aus
        if self.kuehlung == True:
            print("Die Kühlung ist eingeschaltet.")
        else:
            print("Die Kühlung ist ausgeschaltet.")


# eine Getränkeeinheit erzeugen und den Preis übergeben
flasche = Getraenkeeinheit(getraenke_name, getraenke_preis, getraenke_anzahl)
# eine Münzeinheit erzeugen
einheit = Muenzeinheit()
# einen Automaten erzeugen
# die Münzeinheit und die Anzahl der Getränke übergeben
automat = Getraenkeautomat(einheit, flasche)

auswahl = -1
# die Kühlung einschalten
automat.kuehlen(True)

# ein Getränk auswählen
while auswahl == -1:
    auswahl = automat.getraenk_waehlen()

# die Kühlung ausschalten
automat.kuehlen(False)

# die Instanzen ausdrücklich freigeben
# zuerst den Automaten
del automat
# die Getränkeeinheit
del flasche
# die Münzeinheit
del einheit
Nochmals Dank für für eure Hilfe.
Miko
Albo
User
Beiträge: 3
Registriert: Mittwoch 28. April 2021, 12:10

sorry, ich hatte mich in meinem 1. Kommentar verschrieben.
Natürlich soll Rückgeld ausgegeben werden.
In der Vorlage (Vers. 6) wird kein Rückgeld gegeben, was ich ja ändern muss.

Ich werde mein Chaos-Kopf auf reset setzen und nochmals die Lektionen durchgehen.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Zuerst einmal die Vorlage so verbessert, dass sie einigermaßen als Vorlage taugt. __del__ und del entfernen. Unsinnige Kommentare entfernen und statt dessen mit Doc-Strings dokumentieren.
`rueckgeld` ist ein unnötiges Attribut, weil man es einfach ausrechnen kann, was ja auch gemacht wird. Außerdem ist die Berechnung falsch.

Die Variablenamen sind schlecht, und dass Getränkenamen und Anzahl in getrennten Listen verwaltet werden. Aber zweiteres sollst Du ja reparieren.
Ich habe unsinn wie "kuehlen" einfach mal gelöscht, damit es übersichtlicher bleibt:

Code: Alles auswählen

class Muenzeinheit:
    def __init__(self):
        self.betrag = 0
        self.noch_zu_zahlen = 0
        self.rueckgeld = 0

    def muenzen_annehmen(self, wert):
        """ reduziert den noch zu zahlenden Betrag um den übergebenen Wert"""
        self.noch_zu_zahlen -= wert

    def rueckgeld_geben(self):
        """ Gibt den zu viel gezahlten Betrag zurück """
        return max(-self.noch_zu_zahlen, 0)

    def set_betrag(self, preis):
        """ Setzt den zu zahlenden Betrag """
        self.betrag = preis
        self.noch_zu_zahlen = self.betrag


class Getraenkeautomat:
    def __init__(self, anzahl_limonade, anzahl_wasser, anzahl_bier, muenzeinheit):
        self.muenzeinheit = muenzeinheit

        # eine leere Liste für die Getränkenamen  
        self.getraenke_namen = [
            "Limonade",
            "Wasser",
            "Bier"
        ]

        # die Anzahl der Flaschen werden jetzt durch die Argumente gesetzt
        self.anzahl_flaschen = [
            anzahl_limonade,
            anzahl_wasser,
            anzahl_bier
        ]

    def getraenke_waehlen(self):
        """ fragt interaktiv die Anzahl an Getränken ab und wikelt auch schon die Zahlung ab.
        Gibt True bei erfolgreicher Abwicklung zurück und False, falls die Auswahl nicht mehr existiert.
        """
        print("Bitte wählen Sie ein Getränk:")
        print("Es gibt folgende Auswahl:")
        for anzeige_auswahl, getraenk in enumerate(self.getraenke_namen, 1):
            print(f"{anzeige_auswahl}. {getraenk}")

        auswahl = int(input("Geben Sie die gewünschte Nummer ein: ")) - 1

        # gibt es noch Flaschen vom gewählten Getränk?
        if self.anzahl_flaschen[auswahl] == 0:
            print("Das gewählte Getränk ist leider nicht mehr vorhanden.")
            return False
        
        # die Anzahl der Flaschen einlesen
        anzahl = int(input("Wie viele Flaschen möchten Sie? "))

        # erst muss bezahlt werden
        # der Preis 10 ist fest vorgegeben
        betrag = 10 * anzahl
        print(f"Sie müssen {betrag} Cent bezahlen.")
        self.muenzeinheit.set_betrag(betrag)
        while self.muenzeinheit.noch_zu_zahlen > 0:
            print(f"Es fehlen noch {self.muenzeinheit.noch_zu_zahlen} Cent.")
            self.muenzeinheit.muenzen_annehmen(3)

        self._getraenk_ausgeben(anzahl, auswahl)
        return True

    def _getraenk_ausgeben(self, anzahl, getraenke_index):
        """ Gibt die gekauften Getränke aus """
        # gibt es noch genügend Flaschen?
        if anzahl <= self.anzahl_flaschen[getraenke_index]:
            print(f"Sie erhalten {anzahl} Flasche(n) {self.getraenke_namen[getraenke_index]}")
            self.anzahl_flaschen[getraenke_index] -= anzahl
        else:
            print(f"Es sind nur noch {self.anzahl_flaschen[getraenke_index]} Flaschen {self.getraenke_namen[getraenke_index]} vorhanden.")
            print("Sie erhalten den Rest.")
            self.anzahl_flaschen[getraenke_index] = 0
        # Geld zurückgeben
        print(f"Sie erhalten {self.muenzeinheit.rueckgeld_geben()} Cent zurück.")


def main():
    muenzeinheit = Muenzeinheit()
    automat = Getraenkeautomat(10, 20, 30, muenzeinheit)

    while True:
        erfolgreich = automat.getraenke_waehlen()
        if erfolgreich:
            break

if __name__ == "__main__":
    main()
Jetzt kannst Du anfangen, die Listen getraenke_namen und anzahl_flaschen durch eine Liste getraenke zu ersetzen, die Instanzen von einer neuen Getraenk-Klasse enthalten.
Die Instanzen und die Liste erzeugst Du am besten in main und übergibst sie wie die muenzeinheit an __init__.
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Albo,
Laut meiner Aufgabenstellung soll ich den Beispielcode im Studienheft als Vorlage benutzen:
Ich hoffe das heißt nicht du bekommst Abzüge dafür, dass du die Vorlage verbesserst, ...?
Antworten