Hilfe bei einem Programmteil (Listenfunktionen)

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Tobbe94
User
Beiträge: 11
Registriert: Donnerstag 24. September 2020, 09:55

Hallo liebe Mitglieder,

Ich lerne seit ein paar Wochen in einem Online-Kurs Python. Eine Übungsaufgabe dabei ist, ein kleines Programm für einen Gebrauchtwagenhändler zu erstellen, welches "einen neuen Wagen hinzufügen", "fahrzeug verkaufen", "Preis eines Fahrzeugs ändern", "sortiment anzeigen" und "programm beenden beherrschen soll.

Meine aktuellen Schwierigkeiten: Wie baue ich eine korrekte Endlos-Schleife für das Programm (habe es mit range provisorisch gelöst), Wie kann ich die Artikelnummer eineindeutig machen, sodass keine bereits vorhandene Artikelnummer doppelt in der Liste vorkommen kann und wie kann ich ein verkauftes Auto aus der Autoliste löschen? Ich weiß, dass ist sehr viel und für viele sehr einfach, aber ich programmiere erst seit 2 Wochen. Bin um jeden Rat oder Lösungsansatz dankbar!!!

Soweit bin ich aktuell: (darüber hinaus sollen wir eine Klasse "Auto" erstellen, in welcher für jede der oben genannten Auswahlmöglichkeiten Methoden oder Funktionen erstellt werden sollen. Das habe ich bereits in einem anderen File erstell, jedoch noch nicht lauffähig integrieren können...aber eins nach dem anderen :-) )


#Auswahlmöglichkeiten für den Kunden

auswahl = ["1: Neuen Wagen hinzufügen", "2: Fahrzeug verkaufen", "3: Preis eines Fahrzeugs ändern", "4: Sortiment anzeigen", "5: Programm beenden"]

#Modul "Autos" mit Artikelnummer, Marke, Modell, Farbe, Baujahr und Preis

auto_liste = [[1, "BMW", "1er", "Blau", 2018, 30000], [2, "MB", "A", "Schwarz", 2019, 40000], [3, "Opel", "Astra", "Schwarz", "2015", 10000]]


for i in range(1000):
print(auswahl)
eingabe = int(input("Was möchten Sie tun?: "))

if eingabe == 1:
print("Welches Auto soll hinzugefügt werden?")
artnr_neu = int(input("Artikelnummer: "))
#while artnr_neu in auto_liste[0]: <-- hier habe ich versucht die Artn. eineindeutig zu machen, hat nicht geklappt
#input("Diese Nummer ist bereits vergeben! ")
#exit()
marke_neu = str(input("Marke: "))
modell_neu = input("Modell: ")
farbe_neu = str(input("Farbe: "))
baujahr_neu = int(input("Baujahr: "))
preis_neu = float(input("Preis: "))
neues_auto = [marke_neu, modell_neu, farbe_neu, baujahr_neu, preis_neu]
auto_liste.append(neues_auto)
print(auto_liste)

elif eingabe == 2:
print(auto_liste)
verkauftes_auto = input("Welches Auto wurde verkauft?: ")
auto_liste.remove(verkauftes_auto)
print(auto_liste)


elif eingabe == 3:
input("Neuer Preis: ")

elif eingabe == 4:
print(auto_liste)

elif eingabe == 5:
print("Sie haben das Programm verlassen.")
exit()

else:
print("Diese Eingabe ist ungültig!")
continue
Tobbe94
User
Beiträge: 11
Registriert: Donnerstag 24. September 2020, 09:55

Als Anhang kann ich euch noch meine erstellte Klasse "Auto" zeigen, in welchem ich für das ändern des Preises eine Methode geschrieben habe und für den Rest eine Funktion (Die Daten sind gekapselt, weil das so in der Aufgabe stand):


class Auto:
"""
Erstellt das Objekt Auto für einen Autohändler.
"""
def __init__(self, artnr, marke, modell, farbe, baujahr, preis):
"""
Initialisiert ein neues Objekt Auto

Argumente:
* Artikelnummer (int): Artikelnummer (eindeutig)
* Marke (str) : Marke des Autos
* Modell (str): Modell des Autos
* Farbe (str): Farbe des Autos
* Baujahr (int): Baujahr des Autos
* Preis (float): Preis des Autos
"""

self.__artnr = artnr
self.__marke = marke
self.__modell = modell
self.__farbe = farbe
self.__baujahr = baujahr
self.__preis = preis


def get_artnr(self):
return self.__artnr

def get_marke(self):
return self.__marke

def get_modell(self):
return self.__modell

def get_farbe(self):
return self.__farbe

def get_baujahr(self):
return self.__baujahr

def get_preis(self):
return self.__preis

def set_preis(self, preis):
self.__preis = preis


auto_liste = []
auto_liste.append(Auto(1, "BMW", "1er", "Blau", 2018, 30000))
auto_liste.append(Auto(2, "Mercedes", "A", "Schwarz", 2019, 40000))
auto_liste.append(Auto(3, "Opel", "Astra", "Rot", 2015, 10000))

auto_liste[0].set_preis(30000)

print(auto_liste[0].get_preis())
Sirius3
User
Beiträge: 18217
Registriert: Sonntag 21. Oktober 2012, 17:20

Eine Endlosschleife macht man mit `while True:`.
input liefert schon Strings, da ist ein str-Aufruf unnötig.
`exit` hat in einem sauberen Programm nichts verloren. Die Schleife kann per `break` verlassen werden.
`continue` sollte nicht verwendet werden und ist hier auch gar nicht nötig, da die Schleife eh normal weitergeht.
Wenn Du keine doppelten Nummern vergeben willst, dann mußt Du halt alle Nummern durchsuchen, ob es die eingegebene schon gibt.

Zur Klasse: vergiss gleich wieder, dass es doppelte Unterstriche gibt. Da alle Attribute eh durch get_xxx und set_xxx öffentlich ist, kannst Du sie gleich öffentlich lassen und so wird die Klasse deutlich kürzer. Benutze keine Abkürzungen. Wenn Du Artistennummer meinst, schreibe nicht artnr.
Datentypen haben in Variablennamen nichts verloren.

Code: Alles auswählen

class Auto:
    """ Objekt Auto für einen Autohändler. """
    def __init__(self, artikelnummer, marke, modell, farbe, baujahr, preis):
        """
        Initialisiert ein neues Objekt Auto
        
        Argumente:
        * Artikelnummer (int): Artikelnummer (eindeutig)
        * Marke (str) : Marke des Autos
        * Modell (str): Modell des Autos
        * Farbe (str): Farbe des Autos
        * Baujahr (int): Baujahr des Autos
        * Preis (float): Preis des Autos
        """
        self.artikelnummer = artikelnummer
        self.marke = marke
        self.modell = modell
        self.farbe = farbe
        self.baujahr = baujahr
        self.preis = preis

autos = [
    Auto(1, "BMW", "1er", "Blau", 2018, 30000),
    Auto(2, "Mercedes", "A", "Schwarz", 2019, 40000),
    Auto(3, "Opel", "Astra", "Rot", 2015, 10000),
]
autos[0].preis = 29000
print(autos[0].preis)
Benutzeravatar
__blackjack__
User
Beiträge: 13925
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tobbe94: Ich weiss nicht wie der Kurs sonst so ist, aber diese Übungsaufgabe gab es hier vor einiger Zeit schon mal und anscheinend soll so etwas wie Preis ändern, inklusive Interaktion mit dem Nutzer, in eine Methode auf dem `Auto` landen. Das ist *falsch*! Alle Punkte sind einfach Funktionen. Das `Auto` ist eine einfache Datenklasse. Bestenfalls eine Klasse für die Geschäftslogik. Da gehört keine Interaktion mit dem Benutzer rein. Also weder `input()` noch `print()` hat in der `Auto`-Klasse etwas zu suchen.

Wenn der Kurs auf doppelte führende Unterstriche besteht ist das kein Python-Kurs, und wenn Benutzerinteraktion in der `Auto`-Klasse stattfinden soll, dann ist kein guter Kurs um objektorientierte Programmierung zu lernen.

Der Klassendocstring und der von der `__init__()` sind mindestens mal etwas irreführend und enthalten auch Informationen die da nicht drin sein müssen. Das ``class Auto`` ein Objekt `Auto` erzeugt muss man nicht dokumentieren, das sollte klar sein. Und auch das die `__init__()` ein Objekt initialisiert ist superbanal und muss da nicht stehen.

Da die `__init__()` letztlich einfach nur die Attribute setzt die den gleichen Namen haben wie die Argumente würde man auch eher die Attribute im Klassen-Docstring dokumentieren und den Docstring bei der `__init__()` weglassen. In Sphinx wird per Default bei der Autodoc-Erweiterung nur der Docstring der Klasse in die Dokumentation übernommen. Wenn man den der `__init__()` haben möchte muss man das entweder explizit bei jeder Klasse sagen, oder Konfigurieren das nur der Docstring der `__init__()` verwendet werden soll, oder beide nacheinander gesetzt werden.

Edit: Und das diese supersimple Klasse in ein eigenes Modul soll riecht auch komisch. Das ist in Sprachen wie Java üblich aber in Python ist eine Datei ein Modul und ein Modul ist dazu da um zusammengehörige Funktionen und Klassen zu bündeln. Wenn man in jedes Modul nur eine Klasse steckt, hat man eine unnötige sinnfreie Ebene in die Modulhierarchie eingefügt und Module letztendlich sinnentstellt.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Tobbe94
User
Beiträge: 11
Registriert: Donnerstag 24. September 2020, 09:55

Sirius3 hat geschrieben: Donnerstag 24. September 2020, 11:59 Eine Endlosschleife macht man mit `while True:`.
input liefert schon Strings, da ist ein str-Aufruf unnötig.
`exit` hat in einem sauberen Programm nichts verloren. Die Schleife kann per `break` verlassen werden.
`continue` sollte nicht verwendet werden und ist hier auch gar nicht nötig, da die Schleife eh normal weitergeht.
Wenn Du keine doppelten Nummern vergeben willst, dann mußt Du halt alle Nummern durchsuchen, ob es die eingegebene schon gibt.

Zur Klasse: vergiss gleich wieder, dass es doppelte Unterstriche gibt. Da alle Attribute eh durch get_xxx und set_xxx öffentlich ist, kannst Du sie gleich öffentlich lassen und so wird die Klasse deutlich kürzer. Benutze keine Abkürzungen. Wenn Du Artistennummer meinst, schreibe nicht artnr.
Datentypen haben in Variablennamen nichts verloren.

Code: Alles auswählen

class Auto:
    """ Objekt Auto für einen Autohändler. """
    def __init__(self, artikelnummer, marke, modell, farbe, baujahr, preis):
        """
        Initialisiert ein neues Objekt Auto
        
        Argumente:
        * Artikelnummer (int): Artikelnummer (eindeutig)
        * Marke (str) : Marke des Autos
        * Modell (str): Modell des Autos
        * Farbe (str): Farbe des Autos
        * Baujahr (int): Baujahr des Autos
        * Preis (float): Preis des Autos
        """
        self.artikelnummer = artikelnummer
        self.marke = marke
        self.modell = modell
        self.farbe = farbe
        self.baujahr = baujahr
        self.preis = preis

autos = [
    Auto(1, "BMW", "1er", "Blau", 2018, 30000),
    Auto(2, "Mercedes", "A", "Schwarz", 2019, 40000),
    Auto(3, "Opel", "Astra", "Rot", 2015, 10000),
]
autos[0].preis = 29000
print(autos[0].preis)
Vielen Dank für deine schnelle und hilfreiche Anwort. Habe die Endlosschleife nun wie folg geschrieben:

while i = True:

(...Programm)

elif eingabe:
i = False
break

es scheint so zu funktionieren! Passt das so, oder ist das wieder nicht optimal?
Tobbe94
User
Beiträge: 11
Registriert: Donnerstag 24. September 2020, 09:55

__blackjack__ hat geschrieben: Donnerstag 24. September 2020, 13:07 @Tobbe94: Ich weiss nicht wie der Kurs sonst so ist, aber diese Übungsaufgabe gab es hier vor einiger Zeit schon mal und anscheinend soll so etwas wie Preis ändern, inklusive Interaktion mit dem Nutzer, in eine Methode auf dem `Auto` landen. Das ist *falsch*! Alle Punkte sind einfach Funktionen. Das `Auto` ist eine einfache Datenklasse. Bestenfalls eine Klasse für die Geschäftslogik. Da gehört keine Interaktion mit dem Benutzer rein. Also weder `input()` noch `print()` hat in der `Auto`-Klasse etwas zu suchen.

Wenn der Kurs auf doppelte führende Unterstriche besteht ist das kein Python-Kurs, und wenn Benutzerinteraktion in der `Auto`-Klasse stattfinden soll, dann ist kein guter Kurs um objektorientierte Programmierung zu lernen.

Der Klassendocstring und der von der `__init__()` sind mindestens mal etwas irreführend und enthalten auch Informationen die da nicht drin sein müssen. Das ``class Auto`` ein Objekt `Auto` erzeugt muss man nicht dokumentieren, das sollte klar sein. Und auch das die `__init__()` ein Objekt initialisiert ist superbanal und muss da nicht stehen.

Da die `__init__()` letztlich einfach nur die Attribute setzt die den gleichen Namen haben wie die Argumente würde man auch eher die Attribute im Klassen-Docstring dokumentieren und den Docstring bei der `__init__()` weglassen. In Sphinx wird per Default bei der Autodoc-Erweiterung nur der Docstring der Klasse in die Dokumentation übernommen. Wenn man den der `__init__()` haben möchte muss man das entweder explizit bei jeder Klasse sagen, oder Konfigurieren das nur der Docstring der `__init__()` verwendet werden soll, oder beide nacheinander gesetzt werden.

Edit: Und das diese supersimple Klasse in ein eigenes Modul soll riecht auch komisch. Das ist in Sprachen wie Java üblich aber in Python ist eine Datei ein Modul und ein Modul ist dazu da um zusammengehörige Funktionen und Klassen zu bündeln. Wenn man in jedes Modul nur eine Klasse steckt, hat man eine unnötige sinnfreie Ebene in die Modulhierarchie eingefügt und Module letztendlich sinnentstellt.
Hallo! Vielen Dank für deine Antwort! Ich weiß natürlich nicht ob ich die Aufgabenbeschreibung richitg verstanden habe, deshalb hier ist die Aufgabe mal:

1) ​Schreibe ein Programm für einen Gebrauchtwagenhändler. Dieses soll aus einer  Endlosschleife bestehen, die den Anwender fragt, welche Aktion er durchführen will.  Dabei soll er folgende Optionen haben: 
- Neuen Wagen hinzufügen  
- Fahrzeug verkaufen  
- Preis eines Fahrzeugs ändern  
- Sortiment anzeigen   - Programm beenden   
2) ​Die einzelnen Autos sollen in einem Objekt gespeichert werden. Erstelle hierfür in  einem neuen Modul die Klasse Auto. Sie soll die Attribute Artikelnummer, Marke,  Modell, Farbe, Baujahr und Preis enthalten. Diese Daten sollen gekapselt sein.   
3) ​Gestalte daraufhin für jede der oben genannten Aktionen eine passende Methode  oder Funktion, in die du Befehle/Programmteile auslagerst.   Wenn sie ein vorhandenes Objekt verändert, ist eine Methode die richtige Wahl. In  allen anderen Fällen bietet es sich an, eine Funktion zu verwenden.    
4) ​Das gesamte Sortiment soll in einer Liste abgespeichert werden. Diese enthält  Objekte vom Typ Auto. Es ist sinnvoll, wenn der Zugriff auf ein Objekt immer über die  Artikelnummer stattfindet. Dazu ist es wichtig, darauf zu achten, dass jede Nummer nur  ein einziges Mal vergeben wird. 

die Unterstriche benötige ich ja für die Datenkapselung der Attribute der Klasse Auto oder? Im Kurs hieß es, es sei bei sehr einfachen Programmen oftmals nicht notwendig aber für größere Programme bezüglich Sicherheit sollte man davon wissen.
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Warum hast du in das While jetzt noch ein i eingebaut?

vielleicht hilft dir das zur Veranschaulichung:

Code: Alles auswählen

while True:
    eingabe = input("Gib irgendwas ein (zum Abbrechen 'q' eingeben): ")
    if eingabe == 'q':
        break
Tobbe94
User
Beiträge: 11
Registriert: Donnerstag 24. September 2020, 09:55

Jankie hat geschrieben: Donnerstag 24. September 2020, 13:43 Warum hast du in das While jetzt noch ein i eingebaut?

vielleicht hilft dir das zur Veranschaulichung:

Code: Alles auswählen

while True:
    eingabe = input("Gib irgendwas ein (zum Abbrechen 'q' eingeben): ")
    if eingabe == 'q':
        break
Im Kapitel mit while haben wir das immer mit dem i so gemacht. Wusste nicht, dass das so auch geht. Aber so ists natürlich einfacher, danke! Wieder was gelernt :)
Tobbe94
User
Beiträge: 11
Registriert: Donnerstag 24. September 2020, 09:55

Kann mir eventuell noch jemand kurz zeigen, wie ich bei meinem Programm durch einen User-Input eine Liste (Auto) aus meiner Auto-Liste (Autosortiment) löschen kann? Habe versucht den Input-Wert mit einer Variablen zu versehen (verkauftes_auto), welcher dann mit remove aus der Liste entfernt werden soll. Allerdings kommt immer ein ValueError: list.remove(x): x not in list?! Hab da schon stundenlang rumprobiert aber nichts klappt :D
Glaub, das ist das einzige was ich noch nicht kapiere, neben der Preisänderung im Hauptprogramm
garreth
User
Beiträge: 41
Registriert: Donnerstag 23. Oktober 2014, 12:04

Tobbe94 hat geschrieben: Donnerstag 24. September 2020, 13:40 die Unterstriche benötige ich ja für die Datenkapselung der Attribute der Klasse Auto oder? Im Kurs hieß es, es sei bei sehr einfachen Programmen oftmals nicht notwendig aber für größere Programme bezüglich Sicherheit sollte man davon wissen.
Ja, das mag auf andere Programmiersprachen durchaus zutreffen. In Python gibt es aber sowas wie private Funktionen nicht.
Benutzeravatar
__blackjack__
User
Beiträge: 13925
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tobbe94: Du musst nicht immer ganze Beiträge als Zitat einfügen. Wenn Du Dich auf den letzten Beitrag von jemandem beziehst, dann ist ja klar was gemeint ist, denn die kann man ja etwas weiter oben nachlesen.

Ein Zitat macht eigentlich nur Sinn wenn man sich auf eine ganz konkrete Formulierung bezieht, die man nicht im eigenen Beitrag einfach kurz umschreiben oder drauf hinweisen kann.

Du brauchst keine doppelten führenden Unterstriche sondern höchstens einfache Unterstriche. Das ist in Python die Konvention für Attribute die nicht zur öffentlichen API gehören. Doppelte Unterstriche sind dazu da, dass es bei Mehrfachvererbung oder tiefen Klassenhierarchien keine Namenskollisionen gibt. Da man beides kaum bis gar nicht macht, ist es auch ganz selten, dass man das mal braucht. An die Werte zu den Attributen kommt man von aussen in jedem Fall herankommen.

Letztlich gibt es keinen Zugriffsschutz in Python und man sollte den auch nicht versuchen irgendwie rein zu hacken. Oder Begriffe wie ``private`` und ``protected`` irgendwie auf Python abbilden zu wollen. Wenn man so etwas haben will/braucht, sollte man eine Programmiersprache verwenden die das bietet.

Zum ``while i == True:``: Man macht keine Vergleiche mit literalen Wahrheitswerten. Bei dem Vergleich kommt doch nur wieder ein Wahrheitswert bei heraus. Entweder der, den man sowieso schon hatte; dann kann man den auch gleich nehmen. Oder das Gegenteil davon; dafür gibt es ``not``. Also in diesem Fall einfach ``while i:``. Wobei `i` kein guter Name für einen Wahrheitswert ist.

Um ein Auto mit `remove()` aus der Liste zu entfernen, müsstest Du das Auto-Objekt, das entfernt werden soll, an `remove()` übergeben. Und das kann ja kein Eingabewert von `input()` sein, denn das sind Zeichenketten. In der Liste sind aber `Auto`-Objekte. Und ein `Auto`-Objekt ist nie gleich einer Zeichenkette. Also sofern man die Vergleichsoperationen beim `Auto` nicht auf perverse Weise überlädt zumindest.

Du hast, oder Du brauchst, ja irgendwo eine Funktion um zu einer Artikelnummer das dazugehörige Auto-Objekt aus der Liste zu holen. Oder zumindest den Index. Das kannst Du dann entweder mit `remove()` oder `pop()` verwenden um das Auto aus der Liste zu entfernen.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Benutzeravatar
__blackjack__
User
Beiträge: 13925
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich wusste das mir das bekannt vorkommt, und jetzt weiss ich auch wie ich darauf komme das die Benutzerinteraktion scheinbar in die `Auto`-Klasse soll. Das sind Beispiele aus einem Buch, und konkret das `Auto` aus dem Buch ist dieses furchtbare Stück Code: viewtopic.php?f=1&t=46546#p352813
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Tobbe94
User
Beiträge: 11
Registriert: Donnerstag 24. September 2020, 09:55

Könnte ich das nicht mit einem int(input()) umgehen? Mein Idee war, dass der User Anhand der Liste und der Artnr. [ [1,... ], [2,... ], [3, ] ] das zu löschende Auto erkennt. Dann soll der Eingabewert durch die Variable in remove() gepackt werden und den x. Listeneintrag rauslöschen. Beispielsweise User-Eingabe 2 steht für Artnr. 2 und somit wird der zweite Eintrag der Liste gelöscht.
Ist das Schwachsinn oder geht das? Haha ich stelle glaub ich sehr banale fragen aber ich tu mir noch schwer, das alles zu verstehen.

Zum zweiten: ja, scheint irgendwie ein bekanntes Übungsbeispiel zu sein. Ich finde bestimmt irgendwo eine Lösung im Internet, aber das bringt mich persönlich nicht so viel weiter, leider :(
Sirius3
User
Beiträge: 18217
Registriert: Sonntag 21. Oktober 2012, 17:20

Tobbe94 hat geschrieben: Donnerstag 24. September 2020, 14:25Zum zweiten: ja, scheint irgendwie ein bekanntes Übungsbeispiel zu sein. Ich finde bestimmt irgendwo eine Lösung im Internet, aber das bringt mich persönlich nicht so viel weiter, leider :(
Vor allem weil das Beispiel so grottenschlecht ist.

Du mußt beim Programmieren exakt beschreiben, was Du machen willst.
Wenn der Nutzer die Artikelnummer eingibt, dann mußt Du erst den Listeneintrag mit der passenden Artikelnummer suchen.
Wenn Du dann dieses Auto gefunden hast, kannst Du es auch mit remove entfernen.
Tobbe94
User
Beiträge: 11
Registriert: Donnerstag 24. September 2020, 09:55

Hmm...okay? :D werde dann einfach mal weiter rumprobieren. Aber danke schon mal
Tobbe94
User
Beiträge: 11
Registriert: Donnerstag 24. September 2020, 09:55

Habe noch 2 Wochen Zeit, bis ein lauffähiges Programm abgegeben werden muss. Hoffe ich kriege das hin :)
Benutzeravatar
__blackjack__
User
Beiträge: 13925
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Da die zwei Wochen um sind hier mal eine Python-Lösung zu der Aufgabe. Ist keine Musterlösung weil die Aufgabe teilweise ”unpythonisches” verlangt, das hier aber ein Python-Forum ist und kein „wie verkleide ich ein Java-Programm ☕️ als Python 🐍“-Forum. Ist zwar gerade der 🎃Halloween-Monat🎃, aber da müsste das umgekehrt laufen: man verkleidet sich ja als etwas gruseliges 🧟, was in dieser Kombo Java wäre. 😜

Code: Alles auswählen

#!/usr/bin/env python3
from functools import partial

from attr import attrib, attrs


def ask_something(type_description, convert_function, prompt):
    while True:
        try:
            return convert_function(input(prompt))
        except ValueError:
            print(f"Bitte {type_description} eingeben!")


ask_integer = partial(ask_something, "eine ganze Zahl", int)
ask_float = partial(ask_something, "eine Zahl", float)


@attrs(frozen=True)
class MenuItem:
    text = attrib()
    action = attrib(default=lambda cars: print("Noch nicht implementiert!"))


@attrs
class Car:
    article_number = attrib()
    brand = attrib()
    model = attrib()
    color = attrib()
    year_built = attrib()
    price = attrib()

    def __str__(self):
        return (
            f"{self.article_number}: {self.year_built}er {self.brand}"
            f" {self.model} ({self.color}) für {self.price}€"
        )


def get_car(cars, article_number):
    return next(
        (car for car in cars if car.article_number == article_number), None
    )


def ask_car(cars, prompt):
    article_number = ask_integer(prompt)
    return (article_number, get_car(cars, article_number))


def add_car(cars):
    article_number, car = ask_car(cars, "Neue Artikelnummer: ")
    if car:
        print(f"Artikelnummer {article_number} existiert bereits!")
    else:
        cars.append(
            Car(
                article_number,
                input("Marke: "),
                input("Modell: "),
                input("Farbe: "),
                ask_integer("Baujahr: "),
                ask_float("Preis: "),
            )
        )


def sell_car(cars):
    article_number, car = ask_car(cars, "Artikelnummer für Verkauf: ")
    if car:
        cars.remove(car)
    else:
        print(f"Artikelnummer {article_number} existiert nicht!")


def change_car_price(cars):
    article_number, car = ask_car(cars, "Artikelnummer für Preisänderung: ")
    if car:
        print(car)
        car.price = ask_float("Neuer Preis: ")
    else:
        print(f"Artikelnummer {article_number} existiert nicht!")


def show_cars(cars):
    if cars:
        for car in cars:
            print(car)
    else:
        print("Es sind keine Autos im Bestand!")


def main():
    cars = [
        Car(1, "BMW", "1er", "Blau", 2018, 30000),
        Car(2, "Mercedes", "A", "Schwarz", 2019, 40000),
        Car(3, "Opel", "Astra", "Rot", 2015, 10000),
    ]
    menu_items = [
        MenuItem("Wagen hinzufügen.", add_car),
        MenuItem("Fahrzeug verkaufen.", sell_car),
        MenuItem("Preis eines Fahrzeugs ändern.", change_car_price),
        MenuItem("Sortiment anzeigen.", show_cars),
    ]
    while True:
        print()
        for number, menu_item in enumerate(menu_items, 1):
            print(f"{number}) {menu_item.text}")
        print("0) Programm beenden.")

        choice = ask_integer(f"Auswahl (0-{len(menu_items)}): ")
        if choice == 0:
            break

        if 1 <= choice <= len(menu_items):
            menu_items[choice - 1].action(cars)
        else:
            print("Keine gültige Auswahl!")

        input("Eingabetaste um zum Menü zurück zu kehren.")


if __name__ == "__main__":
    main()
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Antworten