Fehlerbehandlung bei Nutzereingabe

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
Galba29
User
Beiträge: 1
Registriert: Samstag 22. Januar 2022, 21:31

Hallo liebes Forum!

Ich programmiere nun schon einige Monate in Python, allerdings habe ich mich bisher kaum mit Nutzereingaben beschäftigt… und nun wo ich es tue, fallen mir einige Verständnisprobleme auf. Deshalb habe ich mich dafür mal hier angemeldet und hoffe, dass mich jemand ein wenig erleuchten kann. :mrgreen:

Folgendes möchte ich umsetzen: Ich benötige durch den Benutzer zwei Eingaben:
1. Eine einzelne Ganzzahl
2. Einen Vektor mit zwingend drei Elementen, der nicht der Nullvektor sein darf.

Für 2. dachte ich bei der Umsetzung an eine Liste, die dementsprechend folgende drei Dinge erfüllen muss:
a) Sie muss zwingend drei Elemente enthalten.
b) Die Elemente dürfen ausschließlich Ganzzahlen sein. (Gleitkommazahlen gingen zusätzlich auch, aber das würde es nur noch unnötig komplizierter machen)
c) Es dürfen nicht alle drei Elemente gleich Null sein.

Ich hin aktuell bereits so weit:

Code: Alles auswählen

def eingabe():  # Gibt eine Liste [int(b), list(a)] zurück. Beispiel: [3, [1, 4, 8]]
	while True:  # Eingabe der einzelnen Ganzzahl b
		try:
			b = int(input("Bitte eine ganze Zahl eingeben,"
		except ValueError:
			print("Ungültige Eingabe. Bitte eine ganze Zahl eingeben: "
		else:
			break
			
	while True:  # Eingabe des Vektors
		try: 
			a = []
			a = [int(i) for i in input("Bitte drei weitere Ganzzahlen in der Form "x y z" eingeben: ").split()]
		except ValueError:
			print("Ungültige Eingabe. Bitte drei ganze Zahlen eingeben."
		else:
			break
		
		return [b, a]		
Kurz: Ich kann mit try-except aktuell lediglich Bedingung b) sicherstellen, weiß aber nicht so ganz, wie ich gleichzeitig auch a) und c) mit unterbringen kann. Ich habe bereits eine zweite Funktion geschrieben, die beide Bedingungen separat überprüft, allerdings ist mir nicht klar, wie ich die Überprüfung vor dem Return-Befehl unterbringen und den Benutzer unmittelbar zu einer neuen Eingabe auffordern kann.

Wie löst man das alles, so dass es gutem Stil entspricht?
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Eingerückt wird in Python mir 4 Leerzeichen. Nicht mit Tabs.
Verwende sprechende, erklärende Namen. a und b sind das nicht.

Unterteile das Problem in kleine Probleme und steck die jeweils in Funltionen.
Du hast eine Funtion, die die Eingabe entgegen nimmt und die Prüfung vornimmt und ggf die Eingabe erneut anfordert, falls sie int() einen ValueError wirft.

Die rufst du in einer Funktion für jede Eingabe auf. Und in der Funktion prüfst du dann auch die weitere Validierung.

Ungetestet:

Code: Alles auswählen

def read_int_from_input(text):
    while True:
        try:
            return(int(input(text)))
        except ValueError:
            print("Ungültige Eingabe")


def get_user_input():
    a_better_name_than_b = read_int_from_input("Bitte eine ganze Zahl eingeben:")
    while True:
        vector = [
            read_int_from_input("Ersten Wert des Vectors angeben:"),
            read_int_from_input("Zweiten Wert des Vectors angeben:"),
            read_int_from_input("Dritten Wert des Vectors angeben:"),
        ]
        if all([v==0 for v in vector]):
            print("Nullvector ungültig")
        else:
            break
    return (a_better_name_than_b, vector)
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Galba29,

ich würde die Eingabe für die Ganzzahl und den Vektor in zwei Funktionen aufspalten.
Nach einem try - except Block ist das "else" nicht zwingend nötig, man kann da also weitere Abfragen anschließen.
"continue" bricht die Abarbeitung des Schleifenkörpers an der Stelle ab. Anders als bei "break" wird die Schleife aber nicht verlassen, sondern wieder neu gestartet.

Code: Alles auswählen

def number_input():
    while True:  # Eingabe der einzelnen Ganzzahl number
        try:
            number = int(input("Bitte eine ganze Zahl eingeben: "))
        except ValueError:
            print("Ungültige Eingabe. Bitte eine ganze Zahl eingeben: ")
        else:
            return number


def vector_input():
    while True:  # Eingabe des Vektors
        try:
            vector = (
                map(
                    int,
                    input("Bitte drei weitere Ganzzahlen in der Form 'x y z' eingeben: ").split(),
                )
            )
        except ValueError:
            print("Ungültige Eingabe. Bitte drei ganze Zahlen eingeben.")
            continue
        if not len(vector) == 3:
            print("Ungültige Eingabe. Nicht genügend Koordinaten für Vektor!")
        elif not all(vector):
            print("Ungültige Eingabe. Ein Nullvektor ist keine gültige Eingabe")
        else:
            return vector


def eingabe():  # Gibt eine Liste [int(b), list(a)] zurück. Beispiel: [3, [1, 4, 8]]
    return [number_input(), vector_input()]


def main():
    user_input = eingabe()
    print(user_input)


if __name__ == "__main__":
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei ``continue`` IMHO nicht wirklich schön ist, weil es eine Sprunganweisung ist, die sich so nicht in der Einrückung widerspiegelt. Wenn man die übersieht, ist es überraschend, und sie verhindert, dass man den Code um etwas erweitern kann, das am Ende jedes Schleifendurchlaufs passiert, und das man einen Teil der ``continue`` enthält nicht so einfach als Funktion aus der Schleife heraus ziehen kann.

Und es geht fast immer genau so einfach ohne ``continue``. Hier mit einem ``else``, wie in der anderen Eingabefunktion auch, das man dann auch an der Einrückung ablesen kann.

"Nicht genügend Koordinaten" ist eventuell falsch und verwirrend, denn diese Ausgabe kommt auch wenn man *mehr* als drei Komponenten eingibt.

Das "weitere" würde ich aus dem Prompt entfernen, denn das davor schon eine Ganzzahl eingegeben wurde, kann die Funktion ja eigentlich nicht wissen, und sollte sie auch nicht. Falls diese Information wichtig ist, müsste man den Prompt als Argument übergeben, an einer Stelle wo der Code das Wissen über beide Eingaben hat.

Code: Alles auswählen

def vector_input():
    while True:
        try:
            vector = list(
                map(
                    int,
                    input(
                        "Bitte drei Ganzzahlen in der Form 'x y z' eingeben: "
                    ).split(),
                )
            )
        except ValueError:
            print("Ungültige Eingabe. Bitte ganze Zahlen eingeben.")
        else:
            if not len(vector) == 3:
                print(
                    "Ungültige Eingabe. Falsche Anzahl Koordinaten für Vektor!"
                )
            elif not all(vector):
                print(
                    "Ungültige Eingabe. Ein Nullvektor ist keine gültige"
                    " Eingabe"
                )
            else:
                return vector
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

__blackjack__ hat geschrieben: Sonntag 23. Januar 2022, 13:15 Wobei ``continue`` IMHO nicht wirklich schön ist, weil es eine Sprunganweisung ist, die sich so nicht in der Einrückung widerspiegelt. Wenn man die übersieht, ist es überraschend, und sie verhindert, dass man den Code um etwas erweitern kann, das am Ende jedes Schleifendurchlaufs passiert, und das man einen Teil der ``continue`` enthält nicht so einfach als Funktion aus der Schleife heraus ziehen kann.
Ja "continue" hat keinen guten Ruf. Das Thema kommt hier ja auch regelmäßig auf. Und diesmal hatte ich eigentlich auch schon drauf gewartet...
Wie du schon sagst, kann man das umgehen, indem man alles was später kommt in den else-Zweig legt. Das führt oft zu einer tieferen Einrückungsebene.
Bei überschaubaren Passagen ziehe ich "continue" deshalb vor.
Antworten