Bitten Sie den Benutzer um Eingabe, bis er eine gültige Antwort gibt

562

Ich schreibe ein Programm, das eine Eingabe vom Benutzer akzeptiert.

#note: Python 2.7 users should use `raw_input`, the equivalent of 3.X's `input`
age = int(input("Please enter your age: "))
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Das Programm funktioniert wie erwartet, solange der Benutzer aussagekräftige Daten eingibt.

C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!

Es schlägt jedoch fehl, wenn der Benutzer ungültige Daten eingibt:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Traceback (most recent call last):
  File "canyouvote.py", line 1, in <module>
    age = int(input("Please enter your age: "))
ValueError: invalid literal for int() with base 10: 'dickety six'

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

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Sorry, I didn't understand that.
Please enter your age: 26
You are able to vote in the United States!

Wie kann ich das Programm dazu bringen, gültige Eingaben anzufordern, anstatt abzustürzen, wenn unsinnige Daten eingegeben werden?

Wie kann ich Werte wie ablehnen -1, die intin diesem Zusammenhang gültig , aber unsinnig sind?

Kevin
quelle

Antworten:

704

Der einfachste Weg, dies zu erreichen, besteht darin, die inputMethode in eine while-Schleife zu setzen. Verwenden continueSie diese Option, wenn Sie schlechte Eingaben erhalten, und breakaus der Schleife, wenn Sie zufrieden sind.

Wenn Ihre Eingabe eine Ausnahme auslösen könnte

Verwenden Sie tryundexcept , um zu erkennen, wann der Benutzer Daten eingibt, die nicht analysiert werden können.

while True:
    try:
        # Note: Python 2.x users should use raw_input, the equivalent of 3.x's input
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        #better try again... Return to the start of the loop
        continue
    else:
        #age was successfully parsed!
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Implementieren Ihrer eigenen Validierungsregeln

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

while True:
    data = input("Please enter a loud message (must be all caps): ")
    if not data.isupper():
        print("Sorry, your response was not loud enough.")
        continue
    else:
        #we're happy with the value given.
        #we're ready to exit the loop.
        break

while True:
    data = input("Pick an answer from A to D:")
    if data.lower() not in ('a', 'b', 'c', 'd'):
        print("Not an appropriate choice.")
    else:
        break

Kombination von Ausnahmebehandlung und benutzerdefinierter Validierung

Beide oben genannten Techniken können zu einer Schleife kombiniert werden.

while True:
    try:
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        continue

    if age < 0:
        print("Sorry, your response must not be negative.")
        continue
    else:
        #age was successfully parsed, and we're happy with its value.
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Alles in einer Funktion zusammenfassen

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

def get_non_negative_int(prompt):
    while True:
        try:
            value = int(input(prompt))
        except ValueError:
            print("Sorry, I didn't understand that.")
            continue

        if value < 0:
            print("Sorry, your response must not be negative.")
            continue
        else:
            break
    return value

age = get_non_negative_int("Please enter your age: ")
kids = get_non_negative_int("Please enter the number of children you have: ")
salary = get_non_negative_int("Please enter your yearly earnings, in dollars: ")

Alles zusammenfügen

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

def sanitised_input(prompt, type_=None, min_=None, max_=None, range_=None):
    if min_ is not None and max_ is not None and max_ < min_:
        raise ValueError("min_ must be less than or equal to max_.")
    while True:
        ui = input(prompt)
        if type_ is not None:
            try:
                ui = type_(ui)
            except ValueError:
                print("Input type must be {0}.".format(type_.__name__))
                continue
        if max_ is not None and ui > max_:
            print("Input must be less than or equal to {0}.".format(max_))
        elif min_ is not None and ui < min_:
            print("Input must be greater than or equal to {0}.".format(min_))
        elif range_ is not None and ui not in range_:
            if isinstance(range_, range):
                template = "Input must be between {0.start} and {0.stop}."
                print(template.format(range_))
            else:
                template = "Input must be {0}."
                if len(range_) == 1:
                    print(template.format(*range_))
                else:
                    expected = " or ".join((
                        ", ".join(str(x) for x in range_[:-1]),
                        str(range_[-1])
                    ))
                    print(template.format(expected))
        else:
            return ui

Bei Verwendung wie:

age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))

Häufige Fallstricke und warum Sie sie vermeiden sollten

Die redundante Verwendung redundanter inputAnweisungen

Diese Methode funktioniert, wird aber allgemein als schlechter Stil angesehen:

data = input("Please enter a loud message (must be all caps): ")
while not data.isupper():
    print("Sorry, your response was not loud enough.")
    data = input("Please enter a loud message (must be all caps): ")

Es mag anfangs attraktiv aussehen, weil es kürzer als die while TrueMethode ist, aber es verstößt gegen das Don't Repeat Yourself- Prinzip der Softwareentwicklung. Dies erhöht die Wahrscheinlichkeit von Fehlern in Ihrem System. Was passiert , wenn Sie durch die Umstellung auf 2,7 zurückzuportieren wollen inputzu raw_input, aber aus Versehen nur zuerst das ändern inputoben? Es SyntaxErrorwartet nur darauf, dass es passiert.

Rekursion wird Ihren Stapel sprengen

Wenn Sie gerade etwas über Rekursion gelernt haben, könnten Sie versucht sein, sie zu verwenden, get_non_negative_intdamit Sie die while-Schleife entsorgen können.

def get_non_negative_int(prompt):
    try:
        value = int(input(prompt))
    except ValueError:
        print("Sorry, I didn't understand that.")
        return get_non_negative_int(prompt)

    if value < 0:
        print("Sorry, your response must not be negative.")
        return get_non_negative_int(prompt)
    else:
        return value

Dies scheint die meiste Zeit gut zu funktionieren, aber wenn der Benutzer genügend oft ungültige Daten eingibt, wird das Skript mit a beendet RuntimeError: maximum recursion depth exceeded. Sie mögen denken, "kein Dummkopf würde 1000 Fehler hintereinander machen", aber Sie unterschätzen den Einfallsreichtum von Dummköpfen!

Kevin
quelle
53
Es macht Spaß, es mit vielen Beispielen zu lesen, ein großes Lob. Unterschätzte Lektion: "Unterschätze nicht den Einfallsreichtum von Narren!"
Vpibano
3
Ich hätte nicht nur die beiden Fragen und Antworten ohnehin positiv bewertet, da sie großartig sind, sondern Sie haben den Deal mit "dickety six" besiegelt. Gut gemacht, @ Kevin.
erekalper
1
Schätzen Sie nicht den Einfallsreichtum von Dummköpfen ... und klugen Angreifern. Ein DOS-Angriff wäre für solche Dinge am einfachsten, aber andere könnten möglich sein.
Solomon Ucko
Können wir den neuen "Walross" -Operator anstelle redundanter Eingaben verwenden? Ist es auch ein schlechter Stil?
J Arun Mani
1
@JArunMani Ich denke nicht, dass es ein schlechter Stil wäre, aber vielleicht etwas weniger lesbar. Sie werden in der Tat nur eine inputpro Schleife haben und die Schleife wird sehr kurz, aber der Zustand könnte ziemlich lang werden ...
Tomerikoo
39

Warum sollten Sie eine machen while Trueund dann aus dieser Schleife ausbrechen, während Sie Ihre Anforderungen auch einfach in die while-Anweisung einfügen können, da Sie nur aufhören möchten, sobald Sie das Alter erreicht haben?

age = None
while age is None:
    input_value = input("Please enter your age: ")
    try:
        # try and convert the string input to a number
        age = int(input_value)
    except ValueError:
        # tell the user off
        print("{input} is not a number, please enter a number only".format(input=input_value))
if age >= 18:
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Dies würde Folgendes ergeben:

Please enter your age: *potato*
potato is not a number, please enter a number only
Please enter your age: *5*
You are not able to vote in the United States.

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

Steven Stip
quelle
22

Obwohl die akzeptierte Antwort erstaunlich ist. Ich möchte auch einen kurzen Hack für dieses Problem teilen. (Dies kümmert sich auch um das negative Altersproblem.)

f=lambda age: (age.isdigit() and ((int(age)>=18  and "Can vote" ) or "Cannot vote")) or \
f(input("invalid input. Try again\nPlease enter your age: "))
print(f(input("Please enter your age: ")))

PS Dieser Code ist für Python 3.x.

aaveg
quelle
1
Beachten Sie, dass dieser Code rekursiv ist, aber hier keine Rekursion erforderlich ist. Wie Kevin sagte, kann er Ihren Stapel sprengen.
PM 2Ring
2
@ PM2Ring - du hast recht. Aber mein Ziel hier war nur zu zeigen, wie "Kurzschluss" lange Codeteile minimieren (verschönern) kann.
Aaveg
11
Warum sollten Sie einer Variablen ein Lambda zuweisen? Verwenden Sie defstattdessen einfach . def f(age):ist viel klarer alsf = lambda age:
GP89
3
In einigen Fällen benötigen Sie das Alter möglicherweise nur einmal, und diese Funktion wird dann nicht verwendet. Möglicherweise möchten Sie eine Funktion verwenden und sie nach Abschluss der Arbeit wegwerfen. Dies ist vielleicht auch nicht der beste Weg, aber es ist definitiv ein anderer Weg (was der Zweck meiner Lösung war).
Aaveg
@aaveg Wie würden Sie diesen Code drehen, um das vom Benutzer angegebene Alter tatsächlich zu speichern?
Tytire Recubans
12

Also habe ich kürzlich mit etwas Ähnlichem herumgespielt und mir die folgende Lösung ausgedacht, die eine Methode verwendet, um Eingaben zu erhalten, die Junk ablehnen, 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:
    """Waits for a single keypress on stdin.
    -- from :: https://stackoverflow.com/a/6599441/4532996
    """

    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # 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)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    try:
        ret = sys.stdin.read(1) # returns a single character
    except KeyboardInterrupt:
        ret = 0
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return ret

def until_not_multi(chars) -> str:
    """read stdin until !(chars)"""
    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:
    """a practical example:
    test if a user can vote based purely on keypresses"""
    print("can you vote? age : ", end="")
    x = int("0" + until_not_multi("0123456789"))
    if not x:
        print("\nsorry, age can only consist of digits.")
        return
    print("your age is", x, "\nYou can vote!" if x >= 18 else "Sorry! you can't vote")

_can_you_vote()

Das komplette Modul finden Sie hier .

Beispiel:

$ ./input_constrain.py
can you vote? age : a
sorry, age can only consist of digits.
$ ./input_constrain.py 
can you vote? age : 23<RETURN>
your age is 23
You can vote!
$ _

Beachten Sie, dass diese Implementierung standardmäßig geschlossen wird, sobald etwas gelesen wird, das keine Ziffer ist. Ich habe danach nicht die Eingabetaste gedrückt a, aber ich musste nach den Zahlen.

Sie können dies mit der thismany()Funktion im selben Modul zusammenführen, um beispielsweise nur drei Ziffern zuzulassen.

Katze
quelle
12

Funktionaler Ansatz oder " Look Mom No Loops! ":

from itertools import chain, repeat

prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Not a number! Try again:  b
Not a number! Try again:  1
1

oder wenn Sie möchten, dass eine "schlechte Eingabe" von einer Eingabeaufforderung wie in anderen Antworten getrennt wird:

prompt_msg = "Enter a number: "
bad_input_msg = "Sorry, I didn't understand that."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Sorry, I didn't understand that.
Enter a number:  b
Sorry, I didn't understand that.
Enter a number:  1
1

Wie funktioniert es?

  1. prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
    Diese Kombination von itertools.chainund itertools.repeaterzeugt einen Iterator, der "Enter a number: "einmal und "Not a number! Try again: "unendlich oft Zeichenfolgen liefert :
    for prompt in prompts:
        print(prompt)
    Enter a number: 
    Not a number! Try again: 
    Not a number! Try again: 
    Not a number! Try again: 
    # ... and so on
  2. replies = map(input, prompts)- Hier mapwerden alle promptsZeichenfolgen aus dem vorherigen Schritt auf die inputFunktion angewendet. Z.B:
    for reply in replies:
        print(reply)
    Enter a number:  a
    a
    Not a number! Try again:  1
    1
    Not a number! Try again:  it doesn't care now
    it doesn't care now
    # and so on...
  3. Wir verwenden filterund str.isdigitfiltern die Zeichenfolgen heraus, die nur Ziffern enthalten:
    only_digits = filter(str.isdigit, replies)
    for reply in only_digits:
        print(reply)
    Enter a number:  a
    Not a number! Try again:  1
    1
    Not a number! Try again:  2
    2
    Not a number! Try again:  b
    Not a number! Try again: # and so on...
    Und um nur die erste Nur-Ziffern-Zeichenfolge zu erhalten, die wir verwenden next.

Andere Validierungsregeln:

  1. String-Methoden: Natürlich können Sie auch andere String-Methoden verwenden str.isalpha, um nur alphabetische Strings oder str.isuppernur Großbuchstaben zu erhalten. Die vollständige Liste finden Sie in den Dokumenten .

  2. Mitgliedschaftstests:
    Es gibt verschiedene Möglichkeiten, dies durchzuführen. Eine davon ist die Verwendung der folgenden __contains__Methode:

    from itertools import chain, repeat
    
    fruits = {'apple', 'orange', 'peach'}
    prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
    replies = map(input, prompts)
    valid_response = next(filter(fruits.__contains__, replies))
    print(valid_response)
    Enter a fruit:  1
    I don't know this one! Try again:  foo
    I don't know this one! Try again:  apple
    apple
  3. Zahlenvergleich:
    Es gibt nützliche Vergleichsmethoden, die wir hier verwenden können. Zum Beispiel für __lt__( <):

    from itertools import chain, repeat
    
    prompts = chain(["Enter a positive number:"], repeat("I need a positive number! Try again:"))
    replies = map(input, prompts)
    numeric_strings = filter(str.isnumeric, replies)
    numbers = map(float, numeric_strings)
    is_positive = (0.).__lt__
    valid_response = next(filter(is_positive, numbers))
    print(valid_response)
    Enter a positive number: a
    I need a positive number! Try again: -5
    I need a positive number! Try again: 0
    I need a positive number! Try again: 5
    5.0

    Wenn Sie keine Dunder-Methoden verwenden möchten (Dunder = doppelter Unterstrich), können Sie jederzeit Ihre eigene Funktion definieren oder die aus dem operatorModul verwenden.

  4. Pfadexistenz:
    Hier kann man die pathlibBibliothek und ihre Path.existsMethode verwenden:

    from itertools import chain, repeat
    from pathlib import Path
    
    prompts = chain(["Enter a path: "], repeat("This path doesn't exist! Try again: "))
    replies = map(input, prompts)
    paths = map(Path, replies)
    valid_response = next(filter(Path.exists, paths))
    print(valid_response)
    Enter a path:  a b c
    This path doesn't exist! Try again:  1
    This path doesn't exist! Try again:  existing_file.txt
    existing_file.txt

Begrenzung der Anzahl der Versuche:

Wenn Sie einen Benutzer nicht foltern möchten, indem Sie ihn unendlich oft nach etwas fragen, können Sie in einem Anruf von ein Limit angeben itertools.repeat. Dies kann mit der Bereitstellung eines Standardwerts für die nextFunktion kombiniert werden:

from itertools import chain, repeat

prompts = chain(["Enter a number:"], repeat("Not a number! Try again:", 2))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies), None)
print("You've failed miserably!" if valid_response is None else 'Well done!')
Enter a number: a
Not a number! Try again: b
Not a number! Try again: c
You've failed miserably!

Eingabedaten vorverarbeiten:

Manchmal möchten wir eine Eingabe nicht ablehnen, wenn der Benutzer sie versehentlich IN GROSSBUCHSTABEN oder mit einem Leerzeichen am Anfang oder Ende der Zeichenfolge angegeben hat. Um diese einfachen Fehler zu berücksichtigen, können wir die Eingabedaten durch Anwenden str.lowerund str.stripMethoden vorverarbeiten . Für den Fall des Mitgliedschaftstests sieht der Code beispielsweise folgendermaßen aus:

from itertools import chain, repeat

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
lowercased_replies = map(str.lower, replies)
stripped_replies = map(str.strip, lowercased_replies)
valid_response = next(filter(fruits.__contains__, stripped_replies))
print(valid_response)
Enter a fruit:  duck
I don't know this one! Try again:     Orange
orange

Im Fall , wenn Sie viele Funktionen nutzen für die Vorverarbeitung haben, könnte es einfacher sein , eine Funktion zu verwenden , um eine Durchführung Funktion Zusammensetzung . Verwenden Sie zum Beispiel die von hier :

from itertools import chain, repeat

from lz.functional import compose

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
process = compose(str.strip, str.lower)  # you can add more functions here
processed_replies = map(process, replies)
valid_response = next(filter(fruits.__contains__, processed_replies))
print(valid_response)
Enter a fruit:  potato
I don't know this one! Try again:   PEACH
peach

Validierungsregeln kombinieren:

In einem einfachen Fall, wenn das Programm beispielsweise nach einem Alter zwischen 1 und 120 Jahren fragt, kann man einfach ein weiteres hinzufügen filter:

from itertools import chain, repeat

prompt_msg = "Enter your age (1-120): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
numeric_replies = filter(str.isdigit, replies)
ages = map(int, numeric_replies)
positive_ages = filter((0).__lt__, ages)
not_too_big_ages = filter((120).__ge__, positive_ages)
valid_response = next(not_too_big_ages)
print(valid_response)

Wenn es jedoch viele Regeln gibt, ist es besser, eine Funktion zu implementieren, die eine logische Konjunktion ausführt . Im folgenden Beispiel werde ich von hier aus ein fertiges verwenden :

from functools import partial
from itertools import chain, repeat

from lz.logical import conjoin


def is_one_letter(string: str) -> bool:
    return len(string) == 1


rules = [str.isalpha, str.isupper, is_one_letter, 'C'.__le__, 'P'.__ge__]

prompt_msg = "Enter a letter (C-P): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(conjoin(*rules), replies))
print(valid_response)
Enter a letter (C-P):  5
Wrong input.
Enter a letter (C-P):  f
Wrong input.
Enter a letter (C-P):  CDE
Wrong input.
Enter a letter (C-P):  Q
Wrong input.
Enter a letter (C-P):  N
N

Wenn jemand für jeden fehlgeschlagenen Fall eine benutzerdefinierte Nachricht benötigt, gibt es leider keinen ziemlich funktionalen Weg. Zumindest konnte ich keinen finden.

Georgy
quelle
Was für eine gründliche und wundervolle Antwort, die Aufschlüsselung der Erklärungen war großartig.
Locane
Wie würde man unter Verwendung Ihres Stils vorgehen, um Leerzeichen zu entfernen und die Eingabe für Mitgliedschaftstests zu verkleinern? Ich möchte keine Menge erstellen, die sowohl Beispiele in Groß- als auch in Kleinbuchstaben enthalten muss. Ich möchte auch Fehler bei der Eingabe von Leerzeichen berücksichtigen.
Austin
1
@Austin Ich habe einen neuen Abschnitt zur Vorverarbeitung hinzugefügt. Schau mal.
Georgy
Das erinnert mich an ReactiveX. Aber vielleicht war das überhaupt von funktionalen Sprachen inspiriert?
Mateen Ulhaq
8

Verwenden von Click :

Click ist eine Bibliothek für Befehlszeilenschnittstellen und bietet Funktionen zum Abfragen einer gültigen Antwort von einem Benutzer.

Einfaches Beispiel:

import click

number = click.prompt('Please enter a number', type=float)
print(number)
Please enter a number: 
 a
Error: a is not a valid floating point value
Please enter a number: 
 10
10.0

Beachten Sie, wie der Zeichenfolgenwert automatisch in einen Float konvertiert wurde.

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

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

age = click.prompt("What's your age?", type=click.IntRange(1, 120))
print(age)
What's your age?: 
 a
Error: a is not a valid integer
What's your age?: 
 0
Error: 0 is not in the valid range of 1 to 120.
What's your age?: 
 5
5

Wir können auch nur eine der Grenzen angeben minoder max:

age = click.prompt("What's your age?", type=click.IntRange(min=14))
print(age)
What's your age?: 
 0
Error: 0 is smaller than the minimum valid value 14.
What's your age?: 
 18
18

Mitgliedschaftstests:

Mit click.ChoiceArt. Standardmäßig wird bei dieser Prüfung zwischen Groß- und Kleinschreibung unterschieden.

choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
Provide a fruit (apple, peach, orange): 
 banana
Error: invalid choice: banana. (choose from apple, peach, orange)
Provide a fruit (apple, peach, orange): 
 OrAnGe
orange

Arbeiten mit Pfaden und Dateien:

Mit einem click.PathTyp können wir nach vorhandenen Pfaden suchen und diese auch auflösen:

path = click.prompt('Provide path', type=click.Path(exists=True, resolve_path=True))
print(path)
Provide path: 
 nonexistent
Error: Path "nonexistent" does not exist.
Provide path: 
 existing_folder
'/path/to/existing_folder

Das Lesen und Schreiben von Dateien kann erfolgen durch click.File:

file = click.prompt('In which file to write data?', type=click.File('w'))
with file.open():
    file.write('Hello!')
# More info about `lazy=True` at:
# https://click.palletsprojects.com/en/7.x/arguments/#file-opening-safety
file = click.prompt('Which file you wanna read?', type=click.File(lazy=True))
with file.open():
    print(file.read())
In which file to write data?: 
         # <-- provided an empty string, which is an illegal name for a file
In which file to write data?: 
 some_file.txt
Which file you wanna read?: 
 nonexistent.txt
Error: Could not open file: nonexistent.txt: No such file or directory
Which file you wanna read?: 
 some_file.txt
Hello!

Andere Beispiele:

Passwort Bestätigung:

password = click.prompt('Enter password', hide_input=True, confirmation_prompt=True)
print(password)
Enter password: 
 ······
Repeat for confirmation: 
 ·
Error: the two entered values do not match
Enter password: 
 ······
Repeat for confirmation: 
 ······
qwerty

Standardwerte:

In diesem Fall erhalten Sie durch einfaches Drücken Enter(oder einer beliebigen Taste) ohne Eingabe eines Werts einen Standardwert:

number = click.prompt('Please enter a number', type=int, default=42)
print(number)
Please enter a number [42]: 
 a
Error: a is not a valid integer
Please enter a number [42]: 

42
Georgy
quelle
3
def validate_age(age):
    if age >=0 :
        return True
    return False

while True:
    try:
        age = int(raw_input("Please enter your age:"))
        if validate_age(age): break
    except ValueError:
        print "Error: Invalid age."
ojas mohril
quelle
2

Aufbauend auf den hervorragenden Vorschlägen von Daniel Q und Patrick Artner finden Sie hier eine noch allgemeinere Lösung.

# Assuming Python3
import sys

class ValidationError(ValueError):  # thanks 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:  # thanks Daniel Q
            print(onerror[type(e)], file=sys.stderr)

Ich habe mich für explizite ifund raiseAnweisungen anstelle von entschieden assert, da die Überprüfung von Zusicherungen möglicherweise deaktiviert ist, während die Validierung immer aktiviert sein sollte, um Robustheit zu gewährleisten.

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

# No validation, equivalent to simple input:
anystr = validate_input("Enter any string: ")

# Get a string containing only letters:
letters = validate_input("Enter letters: ",
    cond=str.isalpha,
    onerror={ValidationError: "Only letters, please!"})

# Get a float in [0, 100]:
percentage = validate_input("Percentage? ",
    cast=float, cond=lambda x: 0.0<=x<=100.0,
    onerror={ValidationError: "Must be between 0 and 100!",
             ValueError: "Not a number!"})

Oder um die ursprüngliche Frage zu beantworten:

age = validate_input("Please enter your age: ",
        cast=int, cond=lambda a:0<=a<150,
        onerror={ValidationError: "Enter a plausible age, please!",
                 ValueError: "Enter an integer, please!"})
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")
João Manuel Rodrigues
quelle
1

Probier diese:-

def takeInput(required):
  print 'ooo or OOO to exit'
  ans = raw_input('Enter: ')

  if not ans:
      print "You entered nothing...!"
      return takeInput(required) 

      ##  FOR Exit  ## 
  elif ans in ['ooo', 'OOO']:
    print "Closing instance."
    exit()

  else:
    if ans.isdigit():
      current = 'int'
    elif set('[~!@#$%^&*()_+{}":/\']+$').intersection(ans):
      current = 'other'
    elif isinstance(ans,basestring):
      current = 'str'        
    else:
      current = 'none'

  if required == current :
    return ans
  else:
    return takeInput(required)

## pass the value in which type you want [str/int/special character(as other )]
print "input: ", takeInput('str')
Pratik Anand
quelle
0

Während ein try/ exceptBlock funktioniert, wäre eine viel schnellere und sauberere Möglichkeit, diese Aufgabe zu erfüllen, die Verwendung str.isdigit().

while True:
    age = input("Please enter your age: ")
    if age.isdigit():
        age = int(age)
        break
    else:
        print("Invalid number '{age}'. Try again.".format(age=age))

if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")
2Cubed
quelle
0

Gute Frage! Sie können dazu den folgenden Code ausprobieren. =)

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

  1. Bitten Sie den Benutzer, ihn / sie einzugeben age.

    1.1. If ageis floatoder intDatentyp:

    • Überprüfen Sie, ob age>=18. Wenn age>=18ja, drucken Sie die entsprechende Ausgabe und beenden Sie das Programm.

    • Überprüfen Sie, ob 0<age<18. Wenn 0<age<18ja, drucken Sie die entsprechende Ausgabe und beenden Sie das Programm.

    • Wenn dies age<=0der Fall ist, bitten Sie den Benutzer erneut, eine gültige Nummer für das Alter einzugeben ( dh fahren Sie mit Schritt 1 fort.)

    1.2. Wenn dies agenicht der Fall ist floatoder der intDatentyp, bitten Sie den Benutzer, sein Alter erneut einzugeben ( dh fahren Sie mit Schritt 1 fort.)

Hier ist der Code.

from ast import literal_eval

''' This function is used to identify the data type of input data.'''
def input_type(input_data):
    try:
        return type(literal_eval(input_data))
    except (ValueError, SyntaxError):
        return str

flag = True

while(flag):
    age = raw_input("Please enter your age: ")

    if input_type(age)==float or input_type(age)==int:
        if eval(age)>=18: 
            print("You are able to vote in the United States!") 
            flag = False 
        elif eval(age)>0 and eval(age)<18: 
            print("You are not able to vote in the United States.") 
            flag = False
        else: print("Please enter a valid number as your age.")

    else: print("Sorry, I didn't understand that.") 
Siddharth Satpathy
quelle
0

Sie können jederzeit eine einfache if-else-Logik anwenden und ifIhrem Code zusammen mit einer forSchleife eine weitere Logik hinzufügen .

while True:
     age = int(input("Please enter your age: "))
     if (age >= 18)  : 
         print("You are able to vote in the United States!")
     if (age < 18) & (age > 0):
         print("You are not able to vote in the United States.")
     else:
         print("Wrong characters, the input must be numeric")
         continue

Dies wird ein unendliches Klo sein und Sie werden gebeten, das Alter auf unbestimmte Zeit einzugeben.

Ep1c1aN
quelle
Dies beantwortet die Frage nicht wirklich. Die Frage war, eine Benutzereingabe zu erhalten, bis sie eine gültige Antwort gibt, nicht auf unbestimmte Zeit .
Georgy
-1

Sie können eine allgemeinere Logik schreiben, damit Benutzer nur eine bestimmte Anzahl von Malen eingeben können, da der gleiche Anwendungsfall in vielen realen Anwendungen auftritt.

def getValidInt(iMaxAttemps = None):
  iCount = 0
  while True:
    # exit when maximum attempt limit has expired
    if iCount != None and iCount > iMaxAttemps:
       return 0     # return as default value

    i = raw_input("Enter no")
    try:
       i = int(i)
    except ValueError as e:
       print "Enter valid int value"
    else:
       break

    return i

age = getValidInt()
# do whatever you want to do.
Mangu Singh Rajpurohit
quelle
1
Sie vergessen, den iCount-Wert nach jeder Schleife zu erhöhen
Hoai-Thu Vuong
-1

Sie können die Eingabeanweisung zu einer while True-Schleife machen, sodass sie wiederholt nach den Eingaben des Benutzers fragt, und diese Schleife dann unterbrechen, wenn der Benutzer die gewünschte Antwort eingibt. Und Sie können Try-and-Except-Blöcke verwenden, um ungültige Antworten zu verarbeiten.

while True:

    var = True

    try:
        age = int(input("Please enter your age: "))

    except ValueError:
        print("Invalid input.")
        var = False

    if var == True:
        if age >= 18:
                print("You are able to vote in the United States.")
                break
        else:
            print("You are not able to vote in the United States.")

Die Variable var ist nur so, dass das Programm nicht "Sie können in den USA nicht abstimmen" zurückgibt, wenn der Benutzer eine Zeichenfolge anstelle einer Ganzzahl eingibt.

user9142415
quelle
-1

Verwenden Sie die Anweisung "while", bis der Benutzer einen wahren Wert eingibt. Wenn der Eingabewert keine Zahl oder ein Nullwert ist, überspringen Sie ihn und versuchen Sie erneut zu fragen und so weiter. Zum Beispiel habe ich versucht, Ihre Frage wirklich zu beantworten. Wenn wir annehmen, dass unser Alter zwischen 1 und 150 liegt, wird der Eingabewert akzeptiert, andernfalls ist es ein falscher Wert. Zum Beenden des Programms kann der Benutzer die Taste 0 verwenden und als Wert eingeben.

Hinweis: Lesen Sie die Kommentare oben im Code.

# If your input value is only a number then use "Value.isdigit() == False".
# If you need an input that is a text, you should remove "Value.isdigit() == False".
def Input(Message):
    Value = None
    while Value == None or Value.isdigit() == False:
        try:        
            Value = str(input(Message)).strip()
        except InputError:
            Value = None
    return Value

# Example:
age = 0
# If we suppose that our age is between 1 and 150 then input value accepted,
# else it's a wrong value.
while age <=0 or age >150:
    age = int(Input("Please enter your age: "))
    # For terminating program, the user can use 0 key and enter it as an a value.
    if age == 0:
        print("Terminating ...")
        exit(0)

if age >= 18 and age <=150: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")
Saeed Zahedian Abroodi
quelle
-1

Eine weitere Lösung für die Verwendung der Eingabevalidierung mithilfe einer benutzerdefinierten ValidationErrorund einer (optionalen) Bereichsvalidierung für ganzzahlige Eingaben:

class ValidationError(ValueError): 
    """Special validation error - its message is supposed to be printed"""
    pass

def RangeValidator(text,num,r):
    """Generic validator - raises 'text' as ValidationError if 'num' not in range 'r'."""
    if num in r:
        return num
    raise ValidationError(text)

def ValidCol(c): 
    """Specialized column validator providing text and range."""
    return RangeValidator("Columns must be in the range of 0 to 3 (inclusive)", 
                          c, range(4))

def ValidRow(r): 
    """Specialized row validator providing text and range."""
    return RangeValidator("Rows must be in the range of 5 to 15(exclusive)",
                          r, range(5,15))

Verwendungszweck:

def GetInt(text, validator=None):
    """Aks user for integer input until a valid integer is given. If provided, 
    a 'validator' function takes the integer and either raises a 
    ValidationError to be printed or returns the valid number. 
    Non integers display a simple error message."""
    print()
    while True:
        n = input(text)
        try:
            n = int(n)

            return n if validator is None else validator(n)

        except ValueError as ve:
            # prints ValidationErrors directly - else generic message:
            if isinstance(ve, ValidationError):
                print(ve)
            else:
                print("Invalid input: ", n)


column = GetInt("Pleased enter column: ", ValidCol)
row = GetInt("Pleased enter row: ", ValidRow)
print( row, column)

Ausgabe:

Pleased enter column: 22
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: -2
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: 2
Pleased enter row: a
Invalid input:  a
Pleased enter row: 72
Rows must be in the range of 5 to 15(exclusive)
Pleased enter row: 9  

9, 2
Patrick Artner
quelle
-1

Hier ist eine sauberere, allgemeinere Lösung, die wiederholte if / else-Blöcke vermeidet: Schreiben Sie eine Funktion, die (Fehler, Fehleraufforderung) Paare in ein Wörterbuch aufnimmt, und führen Sie alle Ihre Wertprüfungen mit Zusicherungen durch.

def validate_input(prompt, error_map):
    while True:
        try:
            data = int(input(prompt))
            # Insert your non-exception-throwing conditionals here
            assert data > 0
            return data
        # Print whatever text you want the user to see
        # depending on how they messed up
        except tuple(error_map.keys()) as e:
            print(error_map[type(e)])

Verwendungszweck:

d = {ValueError: 'Integers only', AssertionError: 'Positive numbers only', 
     KeyboardInterrupt: 'You can never leave'}
user_input = validate_input("Positive number: ", d)
Daniel Q.
quelle
-1

Permanente Benutzereingaben mit rekursiver Funktion :

String

def askName():
    return input("Write your name: ").strip() or askName()

name = askName()

Ganze Zahl

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

und schließlich die Frage Anforderung:

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

responseAge = [
    "You are able to vote in the United States!",
    "You are not able to vote in the United States.",
][int(age < 18)]

print(responseAge)
Roko C. Buljan
quelle
-2

Die einfache Lösung wäre:

while True:
    age = int(input("Please enter your age: "))

    if (age<=0) or (age>120):
        print('Sorry, I did not understand that.Please try again')
        continue
    else:

        if age>=18:
            print("You are able to vote in the United States!")
        else:
            print("You are not able to vote in the United States.")
        break

Erläuterung des obigen Codes: Um ein gültiges Alter zu erhalten, sollte es positiv sein und nicht höher als das normale physische Alter sein, beispielsweise beträgt das Höchstalter 120 Jahre.

Dann können wir den Benutzer nach dem Alter fragen. Wenn die Alterseingabe negativ ist oder mehr als 120 beträgt, betrachten wir die Eingabe als ungültig und bitten den Benutzer, es erneut zu versuchen.

Sobald die gültige Eingabe eingegeben wurde, führen wir eine Überprüfung (unter Verwendung einer verschachtelten if-else-Anweisung) durch, ob das Alter> = 18 ist, oder umgekehrt, und drucken eine Nachricht, ob der Benutzer wahlberechtigt ist

Rohail
quelle
"Bitte geben Sie Ihr Alter ein: sechsunddreißig" ': der gleiche Absturz wie in der Frage angegeben ...
BDL
-2

Nehmen Sie die Eingabe als Zeichenfolge und verwenden Sie isdigit (), um zu überprüfen, ob die Eingabe nur Ziffern enthält, nicht leer, kann nicht -ve sein

while(True):
   #take input as string
   name = input('Enter age : ')
   #check if valid age, only digits
   print( name.isdigit() ) 

run output : 
Enter age : 12
True
Enter age : 
False
Enter age : qwd
False
Enter age : dw3
False
Enter age : 21de
False
Enter age : 1
True
Enter age : -1
False

Dead Pool
quelle
Es beantwortet auch nicht die Frage.
Georgy