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?
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!
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"
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.
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.
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."
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')
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")
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.
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.")
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.")
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."
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')
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 ")