La façon la plus simple d'y parvenir est de mettre la input
méthode dans une boucle while. À utiliser continue
lorsque vous obtenez une mauvaise entrée et break
hors de la boucle lorsque vous êtes satisfait.
Quand votre contribution pourrait soulever une exception
Utilisez try
etexcept
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émentation de vos propres règles de validation
Si vous souhaitez rejeter les 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.")
Tout encapsuler dans une fonction
Si vous devez demander à votre utilisateur un grand nombre de valeurs différentes, il peut être utile de mettre ce code dans une fonction, afin que vous n'ayez 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 tous ensemble
Vous pouvez étendre cette idée pour créer une fonction d'entrée très générique:
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
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 courants et pourquoi les éviter
L'utilisation redondante des input
instructions redondantes
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): ")
Il peut sembler attrayant au départ parce qu'il est plus court que la while True
méthode, mais il viole le principe de développement logiciel Ne pas répéter . Cela augmente la probabilité de bogues dans votre système. Que se passe-t-il si vous souhaitez rétroporter vers la version 2.7 en passant input
à raw_input
, mais modifier accidentellement uniquement la première input
ci-dessus? C'est SyntaxError
juste une attente pour arriver.
La récursion va exploser votre pile
Si vous venez d'apprendre la récursivité, vous pourriez être tenté de l'utiliser get_non_negative_int
pour pouvoir 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 saisit suffisamment de données non valides, le script se terminera par un RuntimeError: maximum recursion depth exceeded
. Vous pensez peut-être "aucun imbécile ne ferait 1000 erreurs d'affilée", mais vous sous-estimez l'ingéniosité des imbéciles!
input
boucle par boucle et la boucle deviendra très courte, mais la condition pourrait devenir assez longue ...Pourquoi voudriez-vous faire un
while True
puis sortir de cette boucle alors que vous pouvez également simplement mettre vos exigences dans l'instruction while car tout ce que vous voulez, c'est arrêter une fois que vous avez l'âge?Cela se traduirait par ce qui suit:
cela fonctionnera car l'âge n'aura jamais de valeur qui n'aura pas de sens et le code suit la logique de votre "processus métier"
la source
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 de l'âge négatif.)
PS Ce code est pour python 3.x.
la source
def
place.def f(age):
est beaucoup plus clair quef = lambda age:
Donc, je déconseillais quelque chose de similaire récemment, et j'ai trouvé la solution suivante, qui utilise un moyen d'obtenir une entrée qui rejette les indésirables, avant même qu'elle ne soit vérifiée de manière logique.
read_single_keypress()
courtoisie https://stackoverflow.com/a/6599441/4532996Vous pouvez trouver le module complet ici .
Exemple:
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 lu. Je n'ai pas appuyé sur Entrée après
a
, mais je devais chercher les chiffres.Vous pouvez fusionner cela avec la
thismany()
fonction du même module pour n'autoriser, par exemple, que trois chiffres.la source
Approche fonctionnelle ou " regardez maman sans boucles! ":
ou si vous voulez avoir un message "mauvaise entrée" séparé d'une invite de saisie comme dans les autres réponses:
Comment ça marche?
itertools.chain
etitertools.repeat
créera un itérateur qui produira des chaînes"Enter a number: "
une fois et"Not a number! Try again: "
un nombre infini de fois:replies = map(input, prompts)
- icimap
, toutes lesprompts
chaînes de l'étape précédente seront appliquées à lainput
fonction. Par exemple:filter
etstr.isdigit
pour filtrer les chaînes qui ne contiennent que des chiffres: Et pour obtenir uniquement la première chaîne de chiffres uniquement que nous utilisonsnext
.Autres règles de validation:
Méthodes de chaîne: Bien sûr, vous pouvez utiliser d'autres méthodes de chaîne comme
str.isalpha
pour obtenir uniquement des chaînes alphabétiques oustr.isupper
pour obtenir uniquement des majuscules. Voir les documents pour la liste complète.Test d'adhésion:
Il existe plusieurs façons de le réaliser. L'un d'eux consiste à utiliser la
__contains__
méthode:Comparaison des nombres:
Il existe des méthodes de comparaison utiles que nous pouvons utiliser ici. Par exemple, pour
__lt__
(<
):Ou, si vous n'aimez pas utiliser les méthodes de dunder (dunder = double-underscore), vous pouvez toujours définir votre propre fonction, ou utiliser celles du
operator
module.Existence de chemin:
Ici, on peut utiliser la
pathlib
bibliothèque et saPath.exists
méthode:Nombre d'essais limité:
Si vous ne voulez pas torturer un utilisateur en lui demandant quelque chose un nombre infini de fois, vous pouvez spécifier une limite dans un appel à
itertools.repeat
. Cela peut être combiné avec la fourniture d'une valeur par défaut à lanext
fonction:Prétraitement des données d'entrée:
Parfois, nous ne voulons pas rejeter une entrée si l'utilisateur l'a accidentellement fournie EN MAJUSCULES ou avec un espace au début ou à la fin de la chaîne. Pour tenir compte de ces erreurs simples, nous pouvons prétraiter les données d'entrée en appliquant les méthodes
str.lower
etstr.strip
. Par exemple, dans le cas d'un test d'appartenance, le code ressemblera à ceci:Dans le cas où vous avez de nombreuses fonctions à utiliser pour le prétraitement, il peut être plus facile d'utiliser une fonction exécutant une composition de fonction . Par exemple, en utilisant celui d' ici :
Combiner les règles de validation:
Pour un cas simple, par exemple, lorsque le programme demande un âge entre 1 et 120 ans, on peut simplement en ajouter un autre
filter
:Mais dans le cas où il existe de nombreuses règles, il est préférable d'implémenter une fonction effectuant une conjonction logique . Dans l'exemple suivant, j'en utiliserai un prêt d' ici :
Malheureusement, si quelqu'un a besoin d'un message personnalisé pour chaque cas d'échec, alors, je le crains, il n'y a pas de moyen assez fonctionnel. Ou, du moins, je n'en ai pas trouvé.
la source
En utilisant Click :
Click est une bibliothèque d'interfaces de ligne de commande et fournit des fonctionnalités pour demander une réponse valide à un utilisateur.
Exemple simple:
Notez comment il a converti automatiquement la valeur de chaîne en un flottant.
Vérification si une valeur se situe dans une plage:
Il existe différents types personnalisés . Pour obtenir un nombre dans une plage spécifique, nous pouvons utiliser
IntRange
:Nous pouvons également spécifier une seule des limites,
min
oumax
:Test d'adhésion:
Utilisation du
click.Choice
type. Par défaut, cette vérification respecte la casse.Utilisation des chemins et des fichiers:
En utilisant un
click.Path
type, nous pouvons vérifier les chemins existants et également les résoudre:La lecture et l'écriture de fichiers peuvent être effectuées par
click.File
:Autres exemples:
Confirmation mot de passe:
Les valeurs par défaut:
Dans ce cas, une simple pression sur Enter(ou sur la touche que vous utilisez) sans entrer de valeur vous donnera une valeur par défaut:
la source
la source
S'appuyant sur les excellentes suggestions de Daniel Q et Patrick Artner, voici une solution encore plus généralisée.
J'ai opté pour explicites
if
et desraise
déclarations au lieu d'unassert
, parce que la vérification d'assertion peut être désactivée, alors que la validation doit toujours être à fournir robustesse.Cela peut être utilisé pour obtenir différents types d'entrée, avec différentes conditions de validation. Par exemple:
Ou, pour répondre à la question d'origine:
la source
Essaye celui-là:-
la source
Bien qu'un bloc
try
/except
fonctionne, une manière beaucoup plus rapide et plus propre d'accomplir cette tâche serait d'utiliserstr.isdigit()
.la source
Bonne question! Vous pouvez essayer le code suivant pour cela. =)
Ce code utilise ast.literal_eval () pour trouver le type de données de l'entrée (
age
). Ensuite, il suit l'algorithme suivant:Voici le code.
la source
Vous pouvez toujours appliquer une logique simple if-else et ajouter une
if
logique de plus à votre code avec unefor
boucle.Ce sera un loo infini et on vous demandera d'entrer l'âge indéfiniment.
la source
Vous pouvez écrire une logique plus générale pour permettre à l'utilisateur d'entrer uniquement un nombre spécifique de fois, car le même cas d'utilisation se produit dans de nombreuses applications du monde réel.
la source
Vous pouvez faire l'instruction en boucle un certain temps afin qu'elle demande à plusieurs reprises l'entrée des utilisateurs, puis rompre cette boucle si l'utilisateur entre la réponse que vous souhaitez. Et vous pouvez utiliser les blocs try et except pour gérer les réponses invalides.
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 ne pouvez pas voter aux États-Unis".
la source
Utilisez l'instruction "while" jusqu'à ce que l'utilisateur saisisse une valeur vraie et si la valeur d'entrée n'est pas un nombre ou s'il s'agit d'une valeur nulle, ignorez-la et essayez de demander à nouveau et ainsi de suite. Par 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 la saisir comme valeur.
la source
Une autre solution pour utiliser la validation des entrées à l'aide d'une
ValidationError
validation de plage personnalisée et (facultative) pour les entrées entières:Usage:
Production:
la source
Voici une solution plus propre et plus généralisée qui évite les blocs if / else répétitifs: écrivez une fonction qui prend (erreur, invite d'erreur) dans un dictionnaire et faites toutes vos vérifications de valeur avec des assertions.
Usage:
la source
Saisie utilisateur persistante utilisant la fonction récursive :
Chaîne
Entier
et enfin, l'exigence de la question:
la source
La solution simple serait:
Explication du code ci-dessus: Pour un âge valide, il doit être positif et ne doit pas être supérieur à l'âge physique normal, par exemple, l'âge maximum est de 120 ans.
Ensuite, nous pouvons demander à l'utilisateur l'âge et si la saisie de l'âge est négative ou supérieure à 120, nous la considérons comme une entrée non valide et demandons à l'utilisateur de réessayer.
Une fois l'entrée valide entrée, nous vérifions (à l'aide d'une instruction imbriquée if-else) si l'âge est> = 18 ou vice versa et imprimons un message si l'utilisateur est habilité à voter
la source
prendre l'entrée comme chaîne et utiliser isdigit () pour vérifier que l'entrée n'a que des chiffres, pas vide, ne peut pas être -ve
la source