Demander à l'utilisateur d'entrer jusqu'à ce qu'il donne une réponse valide

J'écris un programme qui doit accepter l'entrée de l'utilisateur.

#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.")

Cela fonctionne comme prévu si l'utilisateur entre des données sensibles.

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

Mais s'ils font une erreur, alors il se bloque:

C:PythonProjects> 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'

Au lieu de s'écraser, je voudrais essayer d'obtenir l'entrée à nouveau. Comme ceci:

C:PythonProjects> 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!

Comment puis-je accomplir cela? Et si je voulais aussi rejeter des valeurs comme -1, qui est un int VALIDE, mais absurde dans ce contexte?

414
demandé sur Kevin 2014-04-25 17:31:47

13 réponses

Le moyen le plus simple d'y parvenir serait de mettre la méthode input dans une boucle while. Utilisation continue lorsque vous obtenez une mauvaise entrée, et break sortir de la boucle lorsque vous êtes satisfait.

Lorsque votre entrée peut déclencher une Exception

Utilisez try et catch pour détecter quand l'utilisateur entre des données qui ne peuvent pas être analysées.

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.")

Implémenter Vos Propres Règles De Validation

Si vous voulez rejeter des valeurs que Python peut analyser avec succès, vous pouvez ajouter votre propre logique de validation.

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

Combinaison de la gestion des exceptions et de la Validation personnalisée

Les Deux techniques ci-dessus peuvent être combinées en une seule boucle.

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.")

Encapsuler tout dans une fonction

Si vous devez demander à votre Utilisateur beaucoup de valeurs différentes, il peut être utile de mettre ce code dans une fonction, de sorte que vous n'avez pas à le retaper à chaque fois.

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: ")

Mettre Tout Cela Ensemble

Vous pouvez étendre cette idée pour faire une entrée très générique fonction:

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:
                    print(template.format(" or ".join((", ".join(map(str,
                                                                     range_[:-1])),
                                                       str(range_[-1])))))
        else:
            return ui

Avec une utilisation telle que:

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

Pièges communs, et pourquoi vous devriez les éviter

L'utilisation redondante des instructions redondantes input

Cette méthode fonctionne mais est généralement considérée comme un style médiocre:

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): ")

Cela peut sembler attrayant au départ car il est plus court que la méthode while True, mais cela viole le principe Ne vous répétez pas du développement logiciel. Cela augmente la probabilité de bogues dans votre système. Quel si vous voulez rétroporter à 2.7 en changeant input à raw_input, mais changer accidentellement seulement le premier input ci-dessus? C'est un SyntaxError qui attend juste d'arriver.

La Récursivité Va Souffler Votre Pile

Si vous venez d'apprendre la récursivité, vous pourriez être tenté de l'utiliser dans {[17] } afin que vous puissiez disposer de la boucle while.

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

Cela semble fonctionner correctement la plupart du temps, mais si l'utilisateur entre suffisamment de fois des données invalides, le script se terminera par un RuntimeError: maximum recursion depth exceeded. Vous pouvez penser que "pas fool ferait 1000 erreurs d'affilée", mais vous sous-estimez l'ingéniosité des imbéciles!

513
répondu Kevin 2018-03-15 17:37:10

Pourquoi voudriez-vous faire un while True, puis sortir de cette boucle, tandis que vous pouvez également placer vos exigences dans l'énoncé, puisque tout ce que vous voulez est d'arrêter une fois que vous avez l'âge?

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.")

Il en résulterait ce qui suit:

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.

Cela fonctionnera puisque l'âge n'aura jamais une valeur qui n'aura pas de sens et que le code suit la logique de votre "processus métier"

26
répondu Steven Stip 2018-02-24 16:44:54

Bien que la réponse acceptée soit incroyable. Je voudrais également partager un hack rapide pour ce problème. (Cela prend également en charge le problème d'âge négatif.)

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

PS ce code est pour python 2.x et peut être exporté vers 3.X en changeant le fonctions raw_input et print.

15
répondu aaveg 2015-06-28 23:29:47

Donc, je m'amusais avec quelque chose de similaire récemment, et j'ai trouvé la solution suivante, qui utilise un moyen d'obtenir des entrées qui rejettent les indésirables, avant même qu'elles ne soient vérifiées de manière logique.

read_single_keypress() de courtoisie 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()

, Vous pouvez trouver le module complet ici.

Exemple:

$ ./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!
$ _

Notez que la nature de cette implémentation est qu'elle ferme stdin dès que quelque chose qui n'est pas un chiffre est en lecture. Je n'ai pas appuyé sur ENTRÉE après a, mais j'en avais besoin après les chiffres.

Vous pouvez fusionner ceci avec la fonction thismany() dans le même module pour n'autoriser, disons, que trois chiffres.

8
répondu cat 2017-05-23 12:34:45
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."
2
répondu ojas mohril 2016-06-23 10:34:14

Essayez celui-ci:-

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')
2
répondu Pratik Anand 2017-04-30 09:29:28

Pour modifier votre code et corriger l'erreur:

while True:
    try:
       age = int(input("Please enter your age: "))
       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.")
           break
    except ValueError:
       print("Please enter a valid response")
2
répondu ᴡʜᴀᴄᴋᴀᴍᴀᴅᴏᴏᴅʟᴇ3000 2017-08-09 16:19:41

Vous pouvez écrire une logique plus générale pour permettre à l'utilisateur d'entrer seulement un nombre spécifique de fois, car le même cas d'utilisation se produit dans de nombreuses applications du monde réel.

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.
1
répondu Mangu Singh Rajpurohit 2016-11-03 07:49:29

Utiliser "tandis que" l'instruction jusqu'à l'utilisateur d'entrer une valeur et si la valeur d'entrée n'est pas un nombre ou une valeur null sauter et essayer de demander à nouveau et ainsi de suite. Dans l'exemple j'ai essayé de répondre vraiment à votre question. Si nous supposons que notre âge est compris entre 1 et 150, alors la valeur d'entrée est acceptée, sinon c'est une mauvaise valeur. Pour terminer le programme, l'utilisateur peut utiliser la touche 0 et l'entrer en tant que valeur.

Remarque: lire les commentaires en haut du 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.")
1
répondu Saeed Zahedian Abroodi 2018-07-07 09:28:33

Tout en un try/except bloc de travail, beaucoup plus rapide et plus propre pour accomplir cette tâche serait d'utiliser 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.")
0
répondu 2Cubed 2016-06-06 07:15:17

Vous pouvez faire l'instruction input une boucle while True afin qu'elle demande à plusieurs reprises l'entrée des utilisateurs, puis casser cette boucle si l'utilisateur entre la réponse que vous souhaitez. Et vous pouvez utiliser try et except blocks pour gérer les réponses invalides.

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.")

La variable var est juste pour que si l'utilisateur entre une chaîne au lieu d'un entier, le programme ne retournera pas "vous n'êtes pas en mesure de voter aux États-Unis."

0
répondu user9142415 2018-01-03 00:59:37

Utilisez try catch avec une boucle sans fin. Pour vérifier la chaîne vide utiliser une instruction if pour vérifier si la chaîne est vide.

while True:
    name = input("Enter Your Name\n")
    if not name:
        print("I did not understood that")
        continue
    else:
        break

while True:
    try:
        salary = float(input("whats ur salary\n"))
    except ValueError:
        print("I did not understood that")
        continue
    else:
        break

while True:
    try:
        print("whats ur age?")
        age = int(float(input()))
    except ValueError:
        print("I did not understood that")
        continue
    else:
        break

print("Hello "+ name +  "\nYour salary is " + str(salary) + '\nand you will be ' + str(age+1) +' in a Year')
0
répondu Mahesh Sonavane 2018-07-04 13:49:48

Cela continuera à demander à l'utilisateur d'entrer le numéro jusqu'à ce qu'il entre un numéro valide:

#note: Python 2.7 users should use raw_input, the equivalent of 3.X's input
while(1):
    try:
        age = int(input("Please enter your age: "))
        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.")
            break()
    except:
        print("Please only enter numbers ")
0
répondu Ray Hu 2018-09-15 06:25:42