J'écris un programme qui doit accepter les entrées 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 commettent une erreur, alors 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 planter, j'aimerais qu'il essaie à nouveau d'obtenir les informations. Comme ça:
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 cela? Et si je voulais aussi rejeter des valeurs telles que -1
, qui est une int
valide, mais qui n'a pas de sens dans ce contexte?
Le moyen le plus simple d'y parvenir serait de placer la méthode input
dans une boucle while. Utilisez continue
lorsque vous obtenez une mauvaise entrée et break
en dehors de la boucle lorsque vous êtes satisfait.
Utilisez try and catch pour détecter le moment où l'utilisateur entre des données impossibles à analyser.
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.")
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
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.")
Si vous devez demander à votre utilisateur de nombreuses valeurs différentes, il peut être utile de mettre ce code dans une fonction afin de ne pas avoir à 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: ")
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:
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'))
input
redondantesCette 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 paraître attrayant au départ, car il est plus court que la méthode while True
, mais il enfreint le principe ne vous répétez pas du développement logiciel. Cela augmente la probabilité de bugs dans votre système. Que faire si vous voulez effectuer un backport vers 2.7 en changeant input
en raw_input
, mais en modifiant accidentellement uniquement la première input
ci-dessus? C'est une SyntaxError
qui n'attend que se produire.
Si vous venez tout juste d’apprendre la récursion, vous pourriez être tenté de l’utiliser dans 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 entre des données non valides suffisamment de fois, le script se terminera par un RuntimeError: maximum recursion depth exceeded
. Vous pensez peut-être qu’aucun imbécile ne ferait 1000 erreurs de suite, mais vous sous-estimez l’ingéniosité des imbéciles!
Pourquoi voudriez-vous faire un while True
et ensuite sortir de cette boucle alors que vous pouvez simplement mettre vos exigences dans la déclaration while puisque tout ce que vous voulez, c'est vous 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.")
Cela se traduirait par:
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 car l'âge n'aura jamais une valeur qui n'aura aucun sens et le code suit la logique de votre "processus métier"
Bien que la réponse acceptée soit incroyable. Je voudrais aussi partager un petit bidouillage pour résoudre ce problème. (Cela s’occupe aussi du problème de l’âge négatif.)
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: ")))
P.S. Ce code est pour Python 3.x.
Alors, je m'amusais avec quelque chose de similaire récemment et j'ai proposé la solution suivante, qui utilise un moyen d'obtenir une entrée qui rejette les ordures, avant même qu'elle ne soit vérifiée de manière logique.
read_single_keypress()
courtesy 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 lu. Je n'ai pas appuyé sur enter après a
, mais je devais le faire après les chiffres.
Vous pouvez fusionner ceci avec la fonction thismany()
dans le même module pour n’autoriser que, par exemple, 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."
Pour éditer 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")
Essaye celui-là:-
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')
Utilisez l'instruction "while" jusqu'à ce que l'utilisateur saisisse une valeur vraie. Si la valeur entrée n'est pas un nombre ou est une valeur nulle, ignorez-la et essayez de demander à nouveau, etc. Dans l'exemple, j'ai essayé de répondre réellement à votre question. Si nous supposons que notre âge est compris entre 1 et 150, la valeur entrée est acceptée, sinon, il s'agit d'une valeur fausse… .. Pour terminer le programme, l'utilisateur peut utiliser la touche 0 et la saisir comme valeur.
Remarque: lisez 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.")
Click est une bibliothèque pour les interfaces de ligne de commande. Il fournit une fonctionnalité permettant de demander une réponse valide à un utilisateur.
Exemple simple:
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
Notez comment il a automatiquement converti la valeur de la chaîne en float.
Il existe différents types personnalisés fournis. Pour obtenir un nombre dans une plage spécifique, nous pouvons utiliser 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
Nous pouvons également spécifier une seule des limites, min
ou 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
Utiliser le type click.Choice
. Par défaut, cette vérification est sensible à la casse.
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
En utilisant un type click.Path
, nous pouvons vérifier les chemins existants et les résoudre:
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
La lecture et l’écriture de fichiers peuvent être effectuées avec 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!
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
Dans ce cas, en appuyant simplement sur Enter (ou la clé que vous utilisez) sans entrer de valeur, vous en donnera une par défaut:
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
Vous pouvez écrire une logique plus générale pour permettre à l'utilisateur de ne saisir qu'un nombre spécifique de fois, car le même cas d'utilisation se présente dans de nombreuses applications réelles.
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.
S'appuyant sur les excellentes suggestions de Daniel Q et de Patrick Artner, voici une solution encore plus générale.
# 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)
J'ai opté pour des instructions explicites if
et raise
au lieu d'une assert
, Parce que la vérification d'assertions peut être désactivée, .__ alors que la validation devrait toujours être activée pour assurer la robustesse.
Ceci peut être utilisé pour obtenir différents types d'entrée, Avec différentes conditions de validation . Par exemple:
# 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!"})
Ou, pour répondre à la question initiale:
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.")
Bonne question! Vous pouvez essayer le code suivant pour cela. =)
Ce code utilise ast.literal_eval () to trouve le type de données de l’entrée (age
). Ensuite, il suit l'algorithme suivant:
Demander à l'utilisateur de saisir sa/sa
age
.1.1. Si
age
estfloat
ouint
type de données:
Vérifiez si
age>=18
. Siage>=18
, imprimez la sortie appropriée et quittez.Vérifiez si
0<age<18
. Si0<age<18
, imprimez la sortie appropriée et quittez.Si
age<=0
, demandez à l'utilisateur de saisir à nouveau un nombre valide pour l'âge, (i.e. revenez à l'étape 1.)1.2. Si
age
n'est pas un type de donnéesfloat
ouint
, demandez à l'utilisateur de saisir à nouveau son âge (i.e., revenez à l'étape 1.)
Voici le 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.")
Bien qu'un bloc try
/except
fonctionne, un moyen beaucoup plus rapide et plus propre d'accomplir cette tâche consiste à 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.")
Entrée utilisateur persistante à l'aide de fonction récursive :
def askName():
return input("Write your name: ").strip() or askName()
name = askName()
def askAge():
try: return int(input("Enter your age: "))
except ValueError: return askAge()
age = askAge()
et enfin, l'exigence de la question:
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)
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
ou si vous souhaitez avoir un message "entrée incorrecte" séparé d'une invite d'entrée comme dans les autres réponses:
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
prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
Cette combinaison de itertools.chain
et itertools.repeat
créera un itérateur qui générera une chaîne "Enter a number: "
une fois et "Not a number! Try again: "
un nombre infini de fois: 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
replies = map(input, prompts)
- here map
appliquera toutes les chaînes prompts
de l'étape précédente à la fonction input
. Par exemple.: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...
filter
et str.isdigit
pour filtrer les chaînes contenant uniquement des chiffres: 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...
Et pour obtenir uniquement la première chaîne composée uniquement de chiffres, nous utilisons next
. Méthodes de chaîne: Bien sûr, vous pouvez utiliser d'autres méthodes de chaîne telles que str.isalpha
pour obtenir uniquement des chaînes alphabétiques ou str.isupper
pour obtenir uniquement des majuscules. Voir docs pour la liste complète.
Test d'adhésion:
Il existe différentes manières de le réaliser. L'un d'eux consiste à utiliser __contains__
méthode:
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
Comparaison des nombres:
Il existe des méthodes de comparaison utiles que nous pouvons utiliser ici. Par exemple, pour __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
Ou, si vous n'aimez pas cela, vous pouvez toujours définir votre propre fonction ou utiliser celles du module operator
.
Existence de chemin:
On peut ici utiliser la bibliothèque pathlib
et sa méthode Path.exists
:
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
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 de itertools.repeat
. Ceci peut être combiné avec la fourniture d'une valeur par défaut à la fonction next
:
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!
Pour un cas simple, par exemple, lorsque le programme demande un âge compris entre 1 et 120 ans, on peut simplement ajouter une autre variable 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)
Mais dans le cas où il y a beaucoup de règles, il est préférable d'implémenter une fonction effectuant une conjonction logique . Dans l'exemple suivant, je vais utiliser un fichier ready de here :
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
Malheureusement, si quelqu'un a besoin d'un message personnalisé pour chaque cas ayant échoué, alors, j'ai bien peur qu'il n'y ait pas de jolie manière fonctionnelle. Ou du moins, je ne pouvais pas en trouver un.
Utilisez try catch sans fin en boucle. Pour vérifier la présence d'une chaîne vide, utilisez l'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')
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 des paires (d'erreur, d'erreur) dans un dictionnaire et effectuez toutes vos vérifications de valeur avec des assertions.
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)])
Usage:
d = {ValueError: 'Integers only', AssertionError: 'Positive numbers only',
KeyboardInterrupt: 'You can never leave'}
user_input = validate_input("Positive number: ", d)
Une solution supplémentaire pour utiliser la validation d’entrée à l’aide d’une validation ValidationError
personnalisée et d’une plage (facultative) pour les entrées entières:
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))
Usage:
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)
Sortie:
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
Ceci continuera à demander à l'utilisateur d'entrer le numéro jusqu'à ce qu'il entre un nombre 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 ")
Vous pouvez toujours appliquer une logique if-else simple et ajouter une autre logique if
à votre code, ainsi qu'une boucle for
.
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
Ce seront des toilettes infinies et on vous demanderait d'entrer l'âge, indéfiniment.
Vous pouvez faire de l'instruction input une boucle while True afin qu'elle demande à plusieurs reprises l'entrée de l'utilisateur, puis interrompre cette boucle si l'utilisateur entre la réponse souhaitée. Et vous pouvez utiliser try et except block pour traiter les réponses non valides.
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 ne pouvez pas voter aux États-Unis"