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)?

16voto

cat Punkte 3674

Also, ich habe kürzlich mit etwas Ähnlichem herumgespielt und folgende Lösung entwickelt, die eine Möglichkeit verwendet, Eingaben abzulehnen, bevor sie überhaupt auf logische Weise überprüft werden.

read_single_keypress() mit freundlicher Genehmigung von https://stackoverflow.com/a/6599441/4532996

def read_single_keypress() -> str:
    """Wartet auf einen einzelnen Tastendruck auf stdin.
    -- von :: https://stackoverflow.com/a/6599441/4532996
    """

    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # alten Zustand speichern
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # auf roh setzen - die Vorgehensweise stammt aus der termios(3) Manpage.
    attrs = list(attrs_save) # gespeicherte Version kopieren, um zu aktualisieren
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # nicht-blockieren ausschalten
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # einen einzelnen Tastenanschlag lesen
    try:
        ret = sys.stdin.read(1) # gibt ein einzelnes Zeichen zurück
    except KeyboardInterrupt:
        ret = 0
    finally:
        # alten Zustand wiederherstellen
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return ret

def until_not_multi(chars) -> str:
    """Liest stdin, bis !(chars) erreicht wird"""
    import sys
    chars = list(chars)
    y = ""
    sys.stdout.flush()
    while True:
        i = read_single_keypress()
        _ = sys.stdout.write(i)
        sys.stdout.flush()
        if i not in chars:
            break
        y += i
    return y

def _can_you_vote() -> str:
    """Ein praktisches Beispiel:
    Prüfen, ob ein Benutzer nur anhand von Tastendrücken wählen kann"""
    print("Kannst du wählen? Alter : ", end="")
    x = int("0" + until_not_multi("0123456789"))
    if not x:
        print("\nEntschuldigung, das Alter kann nur aus Ziffern bestehen.")
        return
    print("Dein Alter ist", x, "\nDu kannst wählen!" if x >= 18 else "Entschuldigung! Du kannst nicht wählen")

_can_you_vote()

Du findest das komplette Modul hier.

Beispiel:

$ ./input_constrain.py
Kannst du wählen? Alter : a
Entschuldigung, das Alter kann nur aus Ziffern bestehen.
$ ./input_constrain.py 
Kannst du wählen? Alter : 23
Dein Alter ist 23
Du kannst wählen!
$ _

Bitte beachte, dass die Natur dieser Implementierung stdin schließt, sobald etwas, das keine Ziffer ist, gelesen wird. Ich habe nicht nach a enter gedrückt, aber nach den Zahlen musste ich das tun.

Du könntest dies mit der thismany() Funktion im selben Modul kombinieren, um beispielsweise nur drei Ziffern zuzulassen.

7voto

behnaz.sheikhi Punkte 464

Verwenden Sie try-except zum Umgang mit dem Fehler und wiederholen Sie ihn erneut:

while True:
    try:
        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.")
    except Exception as e:
        print("Bitte geben Sie eine Zahl ein")

6voto

Basierend auf den ausgezeichneten Vorschlägen von Daniel Q und Patrick Artner, hier ist eine noch allgemeinere Lösung.

# Unter der Annahme von Python3
import sys

class ValidationError(ValueError):  # Dank Patrick Artner
    pass

def validate_input(prompt, cast=str, cond=(lambda x: True), onerror=None):
    if onerror==None: onerror = {}
    while True:
        try:
            data = cast(input(prompt))
            if not cond(data): raise ValidationError
            return data
        except tuple(onerror.keys()) as e:  # Dank Daniel Q
            print(onerror[type(e)], file=sys.stderr)

Ich habe mich für explizite if und raise Anweisungen entschieden anstatt für ein assert, weil die assertionsprüfung deaktiviert werden kann, während die Validierung immer aktiviert sein sollte, um Robustheit zu gewährleisten.

Dies kann verwendet werden, um verschiedene Arten von Eingaben mit unterschiedlichen Validierungskriterien zu erhalten. Zum Beispiel:

# Keine Validierung, entspricht einfacher Eingabe:
anystr = validate_input("Geben Sie einen beliebigen String ein: ")

# Einen String erhalten, der nur Buchstaben enthält:
letters = validate_input("Geben Sie Buchstaben ein: ",
    cond=str.isalpha,
    onerror={ValidationError: "Nur Buchstaben, bitte!"})

# Eine Gleitkommazahl zwischen [0, 100] erhalten:
percentage = validate_input("Prozentsatz? ",
    cast=float, cond=lambda x: 0.0<=x<=100.0,
    onerror={ValidationError: "Muss zwischen 0 und 100 liegen!",
             ValueError: "Keine Zahl!"})

Oder, um die ursprüngliche Frage zu beantworten:

age = validate_input("Bitte geben Sie Ihr Alter ein: ",
        cast=int, cond=lambda a:0<=a<150,
        onerror={ValidationError: "Geben Sie bitte ein plausibles Alter ein!",
                 ValueError: "Geben Sie bitte eine ganze Zahl 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.")

5voto

ojas mohril Punkte 1975
def validate_age(age):
    if age >=0 :
        return True
    return False

while True:
    try:
        age = int(raw_input("Bitte geben Sie Ihr Alter ein:"))
        if validate_age(age): break
    except ValueError:
        print "Fehler: Ungültiges Alter."

4voto

Siddharth Satpathy Punkte 2433

Gute Frage! Sie können den folgenden Code dafür ausprobieren. =)

Dieser Code verwendet ast.literal_eval(), um den Datentyp der Eingabe (age) zu ermitteln. Anschließend folgt der folgende Algorithmus:

  1. User auffordern, ihr/sein Alter einzugeben.

    1.1. Falls Alter vom Datentyp float oder int ist:

    • Überprüfen, ob Alter>=18 ist. Falls ja, entsprechende Ausgabe drucken und Programm beenden.

    • Überprüfen, ob 0 ist. Falls ja, entsprechende Ausgabe drucken und Programm beenden.

    * Falls `Alter<=0` ist, Benutzer bitten, erneut eine gültige Zahl für das Alter einzugeben (d.h. zurück zu Schritt 1 gehen).

    ``

    1.2. Falls Alter nicht vom Datentyp float oder int ist, Benutzer bitten, erneut ihr/sein Alter einzugeben (d.h. zurück zu Schritt 1 gehen).

    ``

`Hier ist der Code.

from ast import literal_eval

''' Diese Funktion wird verwendet, um den Datentyp der Eingabedaten zu identifizieren.'''
def input_type(input_data):
    try:
        return type(literal_eval(input_data))
    except (ValueError, SyntaxError):
        return str

flag = True

while(flag):
    age = raw_input("Bitte geben Sie Ihr Alter ein: ")

    if input_type(age)==float or input_type(age)==int:
        if eval(age)>=18: 
            print("Sie können in den Vereinigten Staaten wählen!") 
            flag = False 
        elif eval(age)>0 and eval(age)<18: 
            print("Sie können in den Vereinigten Staaten nicht wählen.") 
            flag = False
        else: print("Bitte geben Sie eine gültige Zahl als Ihr Alter ein.")

    else: print("Entschuldigung, das habe ich nicht verstanden.")`

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