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

Apr 25 2014

J'écris un programme qui accepte une 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.")

Le programme fonctionne comme prévu tant que l'utilisateur entre des données significatives.

C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!

Mais cela échoue si l'utilisateur entre des données invalides:

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 que le programme demande à nouveau l'entrée. 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 faire en sorte que le programme demande des entrées valides au lieu de s'écraser lorsque des données non sensibles sont entrées?

Comment puis-je rejeter des valeurs comme -1, qui est valide int, mais absurde dans ce contexte?

Réponses

776 Kevin Apr 25 2014 at 20:31

Le moyen le plus simple d'y parvenir est de placer la inputméthode dans une boucle while. À utiliser continuelorsque vous obtenez une mauvaise entrée et breakhors de la boucle lorsque vous êtes satisfait.

Quand votre contribution pourrait soulever une exception

Utilisez tryetexcept pour détecter lorsque 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.")

Mettre en œuvre 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 avez besoin de demander à votre utilisateur un grand nombre de 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:
                    expected = " or ".join((
                        ", ".join(str(x) for x in range_[:-1]),
                        str(range_[-1])
                    ))
                    print(template.format(expected))
        else:
            return ui

Avec des usages tels que:

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

Les pièges courants et pourquoi vous devriez les éviter

L'utilisation redondante d' inputinstructions 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 sembler attrayant au départ car il est plus court que la while Trueméthode, mais cela viole le principe de ne pas se répéter du développement logiciel. Cela augmente la probabilité de bogues dans votre système. Que faire si vous souhaitez effectuer un rétroportage vers 2.7 en passant inputà raw_input, mais en ne modifiant accidentellement que le premier inputci-dessus? C'est une SyntaxErrorattente juste pour arriver.

La récursion fera exploser votre pile

Si vous venez d'apprendre la récursivité, vous pourriez être tenté de l'utiliser get_non_negative_intpour vous débarrasser 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 "aucun imbécile ne ferait 1000 erreurs d'affilée", mais vous sous-estimez l'ingéniosité des imbéciles!

46 StevenStip Jan 14 2016 at 19:43

Pourquoi feriez-vous un while Truepuis sortez de cette boucle alors que vous pouvez également simplement mettre vos exigences dans l'instruction while puisque tout ce que vous voulez, c'est 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 entraînerait 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 car l'âge n'aura jamais une valeur qui n'aura aucun sens et le code suit la logique de votre "processus métier"

26 aaveg Jun 29 2015 at 06:29

Bien que la réponse acceptée soit incroyable. Je voudrais également partager un hack rapide pour ce problème. (Cela règle également le problème d'â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: ")))

PS Ce code est pour python 3.x.

17 Georgy May 10 2019 at 23:47

Approche fonctionnelle ou " look mum no loops! ":

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 voulez avoir un message de "mauvaise entrée" séparé d'une invite de saisie 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.chainet itertools.repeatcré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:
    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)- ici mapappliquera toutes les promptschaînes de l'étape précédente à la inputfonction. 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 filteret str.isdigitpour filtrer les chaînes qui ne contiennent que 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 de chiffres que 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 comme str.isalphapour obtenir uniquement des chaînes alphabétiques ou str.isupperpour obtenir uniquement des majuscules. Voir la documentation pour la liste complète.

  2. Test d'adhésion:
    il existe plusieurs façons de le réaliser. L'un d'eux consiste à utiliser la __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 utiliser les méthodes dunder (dunder = double-underscore), vous pouvez toujours définir votre propre fonction, ou utiliser celles du operatormodule.

  4. Existence de chemin:
    Ici, on peut utiliser la pathlibbibliothèque et sa Path.existsméthode:

    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
    

Limitation du nombre d'essais:

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. Cela peut être combiné avec la fourniture d'une valeur par défaut à la nextfonction:

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!

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 prendre en compte ces simples erreurs, nous pouvons prétraiter les données d'entrée en appliquant des méthodes str.loweret str.strip. Par exemple, dans le cas du test d'adhésion, le code ressemblera à ceci:

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)
lowercased_replies = map(str.lower, replies)
stripped_replies = map(str.strip, lowercased_replies)
valid_response = next(filter(fruits.__contains__, stripped_replies))
print(valid_response)
Enter a fruit:  duck
I don't know this one! Try again:     Orange
orange

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 fonctions . Par exemple, en utilisant celui d' ici :

from itertools import chain, repeat

from lz.functional import compose

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
process = compose(str.strip, str.lower)  # you can add more functions here
processed_replies = map(process, replies)
valid_response = next(filter(fruits.__contains__, processed_replies))
print(valid_response)
Enter a fruit:  potato
I don't know this one! Try again:   PEACH
peach

Combinaison des 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:

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 existe de nombreuses règles, il est préférable d'implémenter une fonction réalisant une conjonction logique . Dans l'exemple suivant, j'utiliserai un prêt à partir d' ici :

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 échoué, alors, j'ai peur, il n'y a pas de moyen très fonctionnel. Ou du moins, je n'en ai pas trouvé.

13 cat Jan 31 2016 at 10:47

Donc, je déconnais 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()avec la permission de 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 Entrée après a, mais je devais après les chiffres.

Vous pouvez fusionner cela avec la thismany()fonction dans le même module pour n'autoriser que, disons, trois chiffres.

12 Georgy May 11 2019 at 03:17

En utilisant Click :

Click est une bibliothèque pour les interfaces de ligne de commande et fournit des fonctionnalités pour demander une réponse valide à un utilisateur.

Exemple simple:

import click

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 converti automatiquement la valeur de chaîne en flottant.

Vérifier si une valeur est comprise 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, minou 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:

Utilisation du click.Choicetype. 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 click.Pathtype, nous pouvons vérifier les chemins existants et les résoudre également:

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 par 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, appuyez simplement sur Enter(ou sur n'importe quelle touche 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
3 ojasmohril Jun 23 2016 at 17:34
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."
2 JoãoManuelRodrigues Nov 28 2018 at 21:52

S'appuyant sur les excellentes suggestions de Daniel Q et Patrick Artner, voici une solution encore plus généralisée.

# 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 les instructions explicites ifet raiseau lieu de an assert, car la vérification des assertions peut être désactivée, alors que la validation doit toujours être activée pour assurer la robustesse.

Cela 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.")
1 PratikAnand Apr 30 2017 at 16:29

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')
1 np8 Oct 30 2020 at 14:12

Ouais, j'ai 6 ans de retard par rapport au 🎉 mais cette question mérite une réponse plus à jour.

Séparation des préoccupations

Je suis un grand fan de la philosophie Unix "Faites une chose et faites-la bien" . Dans ce type de problème, il est préférable de diviser le problème en

  • Demandez l'entrée avec get_inputjusqu'à ce que l'entrée soit correcte.
  • Validez en validatorfonction. Vous pouvez écrire différents validateurs pour différentes requêtes d'entrée.

Demander une contribution

Il peut être aussi simple que (Python 3+)

def myvalidator(value):
    try:
        value = int(value)
    except ValueError:
        return False
    return value >= 0

def get_input(prompt, validator, on_validationerror):
    while True:
        value = input(prompt)
        if validator(value):
            return value
        print(on_validationerror)

Exemple

In [2]: get_input('Give a positive number: ', myvalidator, 'Please, try again')
Give a positive number: foobar
Please, try again
Give a positive number: -10
Please, try again
Give a positive number: 42
Out[2]: '42'

Remarque sur Python 3.8+

Dans Python 3.8+, vous pouvez utiliser l'opérateur morse

def get_input(prompt, validator, on_validationerror):
    while not validator(value := input(prompt)):
        print(on_validationerror)
    return value 
2Cubed May 31 2016 at 03:47

Bien qu'un bloc try/ exceptfonctionne, un moyen beaucoup plus rapide et plus propre d'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.")
SiddharthSatpathy Dec 18 2018 at 13:17

Bonne question! Vous pouvez essayer le code suivant pour cela. =)

Ce code utilise ast.literal_eval () pour trouver le type de données de input ( age). Ensuite, il suit l'algorithme suivant:

  1. Demandez à l'utilisateur de le saisir age.

    1.1. Si ageest floatou inttype 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 numéro valide pour l'âge, ( c'est -à- dire, revenez à l'étape 1.)

    1.2. Si ce agen'est pas le type de données floatou int, demandez à l'utilisateur de saisir à nouveau son âge ( c'est -à- dire de revenir à 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.") 
Ep1c1aN Jul 01 2019 at 16:36

Vous pouvez toujours appliquer une logique if-else simple et ajouter une iflogique supplémentaire à votre code avec une forboucle.

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 sera un loo infini et on vous demandera d'entrer dans l'âge, indéfiniment.

Liju Aug 17 2020 at 15:24

Le code ci-dessous peut vous aider.

age=(lambda i,f: f(i,f))(input("Please enter your age: "),lambda i,f: i if i.isdigit() else f(input("Please enter your age: "),f))
print("You are able to vote in the united states" if int(age)>=18 else "You are not able to vote in the united states",end='')

Si vous voulez avoir un maximum d'essais, disons 3, utilisez le code ci-dessous

age=(lambda i,n,f: f(i,n,f))(input("Please enter your age: "),1,lambda i,n,f: i if i.isdigit() else (None if n==3 else f(input("Please enter your age: "),n+1,f)))
print("You are able to vote in the united states" if age and int(age)>=18 else "You are not able to vote in the united states",end='')

Remarque: cela utilise la récursivité.

behnaz.sheikhi Sep 09 2020 at 19:30

Utilisez try-except pour gérer l'erreur et répétez-la à nouveau:

while True:
    try:
        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.")
    except Exception as e:
        print("please enter number")