757 Stimmen

Den Benutzer um Eingabe bitten, bis er eine gültige Antwort gibt

Ich schreibe ein Programm, das Benutzereingaben akzeptiert.

#Hinweis: Python-2.7-Benutzer sollten `raw_input` verwenden, das Äquivalent zu 3.X's `input`
age = int(input("Bitte geben Sie Ihr Alter ein: "))
if age >= 18: 
    print("Sie können in den Vereinigten Staaten wählen!")
else:
    print("Sie können in den Vereinigten Staaten nicht wählen.")

Das Programm funktioniert wie erwartet, solange der Benutzer sinnvolle Daten eingibt.

Bitte geben Sie Ihr Alter ein: 23
Sie können in den Vereinigten Staaten wählen!

Aber es scheitert, wenn der Benutzer ungültige Daten eingibt:

Bitte geben Sie Ihr Alter ein: dickety six
Traceback (most recent call last):
  File "canyouvote.py", Zeile 1, in 
    age = int(input("Bitte geben Sie Ihr Alter ein: "))
ValueError: ungültige Dezimalzahl für int() zur Basis 10: 'dickety six'

Statt abzustürzen, möchte ich, dass das Programm erneut nach der Eingabe fragt. So:

Bitte geben Sie Ihr Alter ein: dickety six
Entschuldigung, das habe ich nicht verstanden.
Bitte geben Sie Ihr Alter ein: 26
Sie können in den Vereinigten Staaten wählen!

Wie bitte ich um gültige Eingaben anstelle von Absturz oder Akzeptanz ungültiger Werte (z.B. -1)?

995voto

Kevin Punkte 72013

Der einfachste Weg, dies zu erreichen, besteht darin, die input-Methode in einer While-Schleife zu platzieren. Verwende continue, wenn du eine falsche Eingabe erhältst, und break, wenn du zufrieden bist.

Wenn Ihre Eingabe eine Ausnahme auslösen könnte

Verwenden Sie try und except, um zu erkennen, wenn der Benutzer Daten eingibt, die nicht analysiert werden können.

while True:
    try:
        # Hinweis: Benutzer von Python 2.x sollten raw_input verwenden, das Äquivalent zu 3.x's Eingabe
        alter = int(input("Bitte geben Sie Ihr Alter ein: "))
    except ValueError:
        print("Entschuldigung, das habe ich nicht verstanden.")
        #versuchen Sie es erneut... Zurück zum Anfang der Schleife
        continue
    else:
        #Das Alter wurde erfolgreich analysiert!
        #wir sind bereit, die Schleife zu verlassen.
        break
if alter >= 18: 
    print("Sie können in den Vereinigten Staaten abstimmen!")
else:
    print("Sie können in den Vereinigten Staaten nicht abstimmen.")

Implementieren Ihrer eigenen Validierungsregeln

Wenn Sie Werte ablehnen möchten, die von Python erfolgreich analysiert werden können, können Sie Ihre eigene Validierungslogik hinzufügen.

while True:
    daten = input("Bitte geben Sie eine laute Nachricht ein (muss alles großgeschrieben sein): ")
    if not daten.isupper():
        print("Entschuldigung, Ihre Antwort war nicht laut genug.")
        continue
    else:
        #wir sind zufrieden mit dem gegebenen Wert.
        #wir sind bereit, die Schleife zu verlassen.
        break

while True:
    daten = input("Wählen Sie eine Antwort von A bis D:")
    if daten.lower() not in ('a', 'b', 'c', 'd'):
        print("Keine angemessene Auswahl.")
    else:
        break

Kombinieren von Ausnahmebehandlung und benutzerdefinierter Validierung

Beide obigen Techniken können in einer Schleife kombiniert werden.

while True:
    try:
        alter = int(input("Bitte geben Sie Ihr Alter ein: "))
    except ValueError:
        print("Entschuldigung, das habe ich nicht verstanden.")
        continue

    if alter < 0:
        print("Entschuldigung, Ihre Antwort darf nicht negativ sein.")
        continue
    else:
        #Das Alter wurde erfolgreich analysiert, und wir sind mit seinem Wert zufrieden.
        #wir sind bereit, die Schleife zu verlassen.
        break
if alter >= 18: 
    print("Sie können in den Vereinigten Staaten abstimmen!")
else:
    print("Sie können in den Vereinigten Staaten nicht abstimmen.")

Alles in einer Funktion zusammenfassen

Wenn Sie Ihren Benutzer nach vielen verschiedenen Werten fragen müssen, kann es nützlich sein, diesen Code in eine Funktion zu setzen, damit Sie ihn nicht jedes Mal neu eingeben müssen.

def get_non_negative_int(prompt):
    while True:
        try:
            wert = int(input(prompt))
        except ValueError:
            print("Entschuldigung, das habe ich nicht verstanden.")
            continue

        if wert < 0:
            print("Entschuldigung, Ihre Antwort darf nicht negativ sein.")
            continue
        else:
            break
    return wert

alter = get_non_negative_int("Bitte geben Sie Ihr Alter ein: ")
kinder = get_non_negative_int("Bitte geben Sie die Anzahl Ihrer Kinder ein: ")
gehalt = get_non_negative_int("Bitte geben Sie Ihr jährliches Einkommen in Dollar ein: ")

Alles zusammenfügen

Sie können diese Idee erweitern, um eine sehr generische Eingabefunktion zu erstellen:

def sanitised_input(prompt, type_=None, min_=None, max_=None, range_=None):
    if min_ ist nicht None und max_ ist nicht None und max_ < min_:
        raise ValueError("min_ muss kleiner oder gleich max_ sein.")
    while True:
        ui = input(prompt)
        if type_ ist nicht None:
            try:
                ui = type_(ui)
            except ValueError:
                print("Eingabetyp muss {0} sein.".format(type_.__name__))
                continue
        if max_ ist nicht None und ui > max_:
            print("Eingabe muss kleiner oder gleich {0} sein.".format(max_))
        elif min_ ist nicht None und ui < min_:
            print("Eingabe muss größer oder gleich {0} sein.".format(min_))
        elif range_ ist nicht None und ui not in range_:
            if isinstance(range_, range):
                template = "Eingabe muss zwischen {0.start} und {0.stop} sein."
                print(template.format(range_))
            else:
                template = "Eingabe muss {0} sein."
                if len(range_) == 1:
                    print(template.format(*range_))
                else:
                    expected = " oder ".join((
                        ", ".join(str(x) for x in range_[:-1]),
                        str(range_[-1])
                    ))
                    print(template.format(expected))
        else:
            return ui

Mit Verwendung wie:

alter = sanitised_input("Geben Sie Ihr Alter ein: ", int, 1, 101)
antwort = sanitised_input("Geben Sie Ihre Antwort ein: ", str.lower, range_=('a', 'b', 'c', 'd'))

Gängige Fallstricke und warum Sie sie vermeiden sollten

Die redundante Verwendung von redundanten input-Anweisungen

Diese Methode funktioniert, wird jedoch im Allgemeinen als schlechter Stil angesehen:

daten = input("Bitte geben Sie eine laute Nachricht ein (muss alles großgeschrieben sein): ")
while not daten.isupper():
    print("Entschuldigung, Ihre Antwort war nicht laut genug.")
    daten = input("Bitte geben Sie eine laute Nachricht ein (muss alles großgeschrieben sein): ")

Es mag anfangs attraktiv aussehen, weil es kürzer ist als die Methode while True, verstößt jedoch gegen das Don't Repeat Yourself Prinzip der Softwareentwicklung. Dies erhöht die Wahrscheinlichkeit von Fehlern in Ihrem System. Was ist, wenn Sie zurückportieren möchten auf 2.7, indem Sie input in raw_input ändern, aber versehentlich nur das erste input oben ändern? Es ist ein SyntaxError, der nur darauf wartet, zu passieren.

Rekursion wird Ihren Stack sprengen

Wenn Sie gerade erst etwas über Rekursion gelernt haben, könnten Sie versucht sein, sie in get_non_negative_int zu verwenden, damit Sie die While-Schleife beseitigen können.

def get_non_negative_int(prompt):
    try:
        wert = int(input(prompt))
    except ValueError:
        print("Entschuldigung, das habe ich nicht verstanden.")
        return get_non_negative_int(prompt)

    if wert < 0:
        print("Entschuldigung, Ihre Antwort darf nicht negativ sein.")
        return get_non_negative_int(prompt)
    else:
        return wert

Dies scheint die meiste Zeit gut zu funktionieren, aber wenn der Benutzer häufig genug ungültige Daten eingibt, wird das Skript mit einem RuntimeError: maximum recursion depth exceeded beendet. Sie könnten denken "kein Narr würde 1000 Fehler hintereinander machen", aber Sie unterschätzen die Genialität der Narren!

63voto

Steven Stip Punkte 397

Warum würdest du ein while True machen und dann aus dieser Schleife ausbrechen, wenn du auch einfach deine Anforderungen in der while-Anweisung platzieren kannst, da du nur stoppen möchtest, wenn du das Alter hast?

age = None
while age is None:
    input_value = input("Bitte geben Sie Ihr Alter ein: ")
    try:
        # Versuche, die Eingabe in eine Zahl umzuwandeln
        age = int(input_value)
    except ValueError:
        # Benachrichtige den Benutzer
        print("{input} ist keine Zahl, bitte geben Sie nur eine Zahl ein".format(input=input_value))
if age >= 18:
    print("Sie können in den Vereinigten Staaten wählen!")
else:
    print("Sie können in den Vereinigten Staaten nicht wählen.")

Das würde zu folgendem Ergebnis führen:

Bitte geben Sie Ihr Alter ein: *Kartoffel*
Kartoffel ist keine Zahl, bitte geben Sie nur eine Zahl ein
Bitte geben Sie Ihr Alter ein: *5*
Sie können in den Vereinigten Staaten nicht wählen.

Dies funktioniert, da das Alter niemals einen Wert haben wird, der keinen Sinn ergibt, und der Code der Logik Ihres "Geschäftsprozesses" folgt.

30voto

aaveg Punkte 1864

Auch wenn die akzeptierte Antwort erstaunlich ist, möchte ich auch einen schnellen Hack für dieses Problem teilen. (Dies löst auch das Problem des negativen Alters.)

f=lambda age: (age.isdigit() and ((int(age)>=18  and "Kann wählen" ) or "Kann nicht wählen")) or \
f(input("Ungültige Eingabe. Versuchen Sie es erneut\nBitte geben Sie Ihr Alter ein: "))
print(f(input("Bitte geben Sie Ihr Alter ein: ")))

P.S. Dieser Code ist für Python 3.x.

23voto

Georgy Punkte 9744

Verwendung von Click:

Click ist eine Bibliothek für Befehlszeilenschnittstellen und bietet Funktionalität für das Abrufen einer gültigen Antwort vom Benutzer.

Einfaches Beispiel:

import click

number = click.prompt('Bitte geben Sie eine Zahl ein', type=float)
print(number)

Bitte geben Sie eine Zahl ein: 
 a
Fehler: a ist kein gültiger Gleitkommawert
Bitte geben Sie eine Zahl ein: 
 10
10.0

Bemerkenswert ist, wie es den Zeichenfolgenwert automatisch in einen Gleitkommawert umgewandelt hat.

Überprüfung, ob ein Wert innerhalb eines Bereichs liegt:

Es gibt verschiedene benutzerdefinierte Typen. Um eine Zahl in einem bestimmten Bereich zu erhalten, können wir IntRange verwenden:

alter = click.prompt("Wie alt sind Sie?", type=click.IntRange(1, 120))
print(alter)

Wie alt sind Sie?: 
 a
Fehler: a ist keine gültige Ganzzahl
Wie alt sind Sie?: 
 0
Fehler: 0 liegt nicht im gültigen Bereich von 1 bis 120.
Wie alt sind Sie?: 
 5
5

Wir können auch nur eine der Grenzen, min oder max, angeben:

alter = click.prompt("Wie alt sind Sie?", type=click.IntRange(min=14))
print(alter)

Wie alt sind Sie?: 
 0
Fehler: 0 ist kleiner als der minimale gültige Wert 14.
Wie alt sind Sie?: 
 18
18

Überprüfung der Mitgliedschaft:

Verwendung des Typs click.Choice. Standardmäßig ist diese Überprüfung im Bezug auf Groß- und Kleinschreibung.

auswahl = {'Apfel', 'Orange', 'Pfirsich'}
wahl = click.prompt('Geben Sie eine Frucht ein', type=click.Choice(auswahl, case_sensitive=False))
print(wahl)

Geben Sie eine Frucht ein (Apfel, Pfirsich, Orange): 
 Banane
Fehler: ungültige Auswahl: Banane. (wählen Sie aus Apfel, Pfirsich, Orange)
Geben Sie eine Frucht ein (Apfel, Pfirsich, Orange): 
 OrAnGe
Orange

Arbeiten mit Pfaden und Dateien:

Durch die Verwendung des Typs click.Path können wir vorhandene Pfade überprüfen und sie auch auflösen:

pfad = click.prompt('Pfad angeben', type=click.Path(exists=True, resolve_path=True))
print(pfad)

Pfad angeben: 
 nichtvorhanden
Fehler: Pfad "nichtvorhanden" existiert nicht.
Pfad angeben: 
 vorhandener_ordner
'/pfad/zum/vorhandenen_ordner

Lesen und Schreiben von Dateien kann mit click.File erfolgen:

datei = click.prompt('In welche Datei soll Daten geschrieben werden?', type=click.File('w'))
with datei.open():
    datei.write('Hallo!')
# Weitere Informationen zu `lazy=True` unter:
# https://click.palletsprojects.com/en/7.x/arguments/#file-opening-safety
datei = click.prompt('Welche Datei möchten Sie lesen?', type=click.File(lazy=True))
with datei.open():
    print(datei.read())

In welche Datei soll Daten geschrieben werden?: 
         # <-- eingegeben: eine leere Zeichenfolge, was kein gültiger Name für eine Datei ist
In welche Datei soll Daten geschrieben werden?: 
 einige_datei.txt
Welche Datei möchten Sie lesen?: 
 nichtvorhandene.txt
Fehler: Datei konnte nicht geöffnet werden: nichtvorhandene.txt: Datei oder Verzeichnis nicht gefunden
Welche Datei möchten Sie lesen?: 
 einige_datei.txt
Hallo!

Weitere Beispiele:

Passwortbestätigung:

passwort = click.prompt('Geben Sie das Passwort ein', hide_input=True, confirmation_prompt=True)
print(passwort)

Geben Sie das Passwort ein: 
 ······
Wiederholen zur Bestätigung: 
 ·
Fehler: die beiden eingegebenen Werte stimmen nicht überein
Geben Sie das Passwort ein: 
 ······
Wiederholen zur Bestätigung: 
 ······
qwerty

Standardwerte:

In diesem Fall führt das einfache Drücken der Enter-Taste (oder einer anderen verwendeten Taste) ohne die Eingabe eines Werts zu einem Standardwert:

nummer = click.prompt('Bitte geben Sie eine Zahl ein', type=int, default=42)
print(nummer)

Bitte geben Sie eine Zahl ein [42]: 
 a
Fehler: a ist keine gültige Ganzzahl
Bitte geben Sie eine Zahl ein [42]: 

42

21voto

np8 Punkte 19969

Ich bin ein großer Fan der Unix-Philosophie "Mache eine Sache und mache sie gut". Die Erfassung von Benutzereingaben und deren Validierung sind zwei separate Schritte:

  • Aufforderung des Benutzers zur Eingabe mit get_input bis die Eingabe in Ordnung ist
  • Validierung mithilfe einer validator-Funktion, die an get_input übergeben werden kann

Es kann so einfach wie möglich gehalten werden (Python 3.8+, mit dem Walross-Operator):

def get_input(
    prompt="Geben Sie einen Wert ein: ",
    validator=lambda x: True,
    error_message="Ungültige Eingabe. Bitte versuchen Sie es erneut.",
):
    while not validator(value := input(prompt)):
        print(error_message)
    return value

def is_positive_int(value):
    try:
        return int(value) >= 0
    except ValueError:
        return False

if __name__ == "__main__":
    val = get_input("Geben Sie eine positive Zahl ein: ", is_positive_int)
    print(f"OK, danke für {val}")

Beispielausführung:

Geben Sie eine positive Zahl ein: -5
Ungültige Eingabe. Bitte versuchen Sie es erneut.
Geben Sie eine positive Zahl ein: asdf
Ungültige Eingabe. Bitte versuchen Sie es erneut.
Geben Sie eine positive Zahl ein:
Ungültige Eingabe. Bitte versuchen Sie es erneut.
Geben Sie eine positive Zahl ein: 42
OK, danke für 42

In Python < 3.8 könnten Sie get_input wie folgt verwenden:

def get_input(
    prompt="Geben Sie einen Wert ein: ",
    validator=lambda x: True,
    error_message="Ungültige Eingabe. Bitte versuchen Sie es erneut.",
):
    while True:
        value = input(prompt)
        if validator(value):
            return value
        print(error_message)

Sie könnten auch KeyboardInterrupt behandeln und eine freundliche Exit-Nachricht anzeigen, bevor die Anwendung beendet wird. Ein Zähler kann verwendet werden, um die erlaubten Wiederholungen gegebenenfalls zu begrenzen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X