548 votes

Demander l'entrée de l'utilisateur jusqu'à ce qu'il donne une réponse valide

Je suis en train d'écrire 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:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!

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

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'

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

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!

Comment puis-je accomplir? Que faire si je voulais aussi rejeter des valeurs comme l' -1, ce qui est valide int, mais pas de sens dans ce contexte?

682voto

Kevin Points 17955

La plus simple façon d'y parvenir serait de mettre la input méthode dans une boucle while. Utiliser continue lorsque vous obtenez la mauvaise entrée, et break hors de la boucle lorsque vous êtes satisfait.

Lors de Votre Entrée Peut Soulever une Exception

Utiliser try et catch pour détecter lorsque l'utilisateur entre des données qui ne peut pas être analysée.

while True:
    try:
        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.")

La Mise En Œuvre Des Règles De Validation

Si vous souhaitez refuser les valeurs que Python peut analyser correctement, 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

En combinant la gestion des exceptions et de 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.")

L'encapsulation dans une Fonction

Si vous devez demander à votre utilisateur pour un grand nombre de valeurs différentes, il peut être utile de placer ce code dans une fonction, de sorte que vous ne pas avoir à 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 tous ensemble

Vous pouvez étendre cette idée de faire une très générique d'entrée de la 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 l'utilisation de tels que:

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

Les Pièges les plus courants, et Pourquoi vous Devriez les Éviter

La Redondant Utilisation de la redondance input des Déclarations

Cette méthode fonctionne, mais est généralement considéré comme mauvais style:

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

Il peut sembler attrayant d'abord parce que c'est plus courte que l' while True méthode, mais il viole l' Don't Repeat Yourself principe de développement de logiciels. Cela augmente la probabilité de bugs dans votre système. Que faire si vous voulez backport à 2,7 en changeant input de raw_input, mais accidentellement modifier uniquement la première input - dessus? C'est un SyntaxError juste en attente de se produire.

La Récursivité Va Souffler Votre Pile

Si vous avez appris à propos de la récursivité, vous pourriez être tenté de l'utiliser en get_non_negative_int de sorte que vous pouvez 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 bien fonctionner la plupart du temps, mais si l'utilisateur entre des données non valides assez de temps, le script va se terminer avec une RuntimeError: maximum recursion depth exceeded. Vous pouvez penser "ne serait fou de faire 1000 erreurs dans une rangée", mais vous êtes en sous-estimer l'ingéniosité des imbéciles!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X