web-dev-qa-db-fra.com

Demander à l'utilisateur de saisir jusqu'à ce qu'il réponde correctement

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?

449
Kevin

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.

Quand votre entrée pourrait soulever une exception

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

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

Encapsuler le tout dans une fonction

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

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:
                    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 courants et pourquoi les éviter

Utilisation redondante de déclarations input 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): ")

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.

La récursion fera sauter votre pile

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!

558
Kevin

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"

30
Steven Stip

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.

20
aaveg

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.

10
cat
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."
3
ojas mohril

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")
3
whackamadoodle3000

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')
3
Pratik Anand

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

Utilisation de Cliquez sur :

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.

Vérifier si une valeur est dans une plage:

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

Test d'adhésion:

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

Travailler avec des chemins et des fichiers:

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!

Autres exemples:

Confirmation mot de passe:

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

Les valeurs par défaut:

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
1
Georgy

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

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:

  1. Demander à l'utilisateur de saisir sa/sa age.

    1.1. Si age est float ou int type de données:

    • Vérifiez si age>=18. Si age>=18, imprimez la sortie appropriée et quittez.

    • Vérifiez si 0<age<18. Si 0<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ées float ou int, 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.") 
0
Siddharth Satpathy

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.")
0
2Cubed

Entrée utilisateur persistante à l'aide de fonction récursive :

Chaîne

def askName():
    return input("Write your name: ").strip() or askName()

name = askName()

Entier

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)
0
Roko C. Buljan

Approche fonctionnelle ou "regarde maman pas de boucles!":

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

Comment ça marche?

  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
    
  2. 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...
    
  3. Nous utilisons 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 .

Autres règles de validation:

  1. 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.

  2. 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
    
  3. 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 .

  4. 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
    

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 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!

Combinaison de règles de validation:

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.

0
Georgy

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')
0
Mahesh Sonavane

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)
0
Daniel Q

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
0
Patrick Artner

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 ")
0
Ray Hu

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.

0
Ep1c1aN

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"

0
user9142415