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 "mauvaise saisie" 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 cela fonctionne-t-il ?
-
prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
Cette combinaison de itertools.chain
y itertools.repeat
créera un itérateur qui donnera des chaînes de caractères "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)
- ici map
appliquera tous les prompts
de l'étape précédente au input
fonction. 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...
-
Nous utilisons filter
y str.isdigit
pour filtrer les chaînes de caractères 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 chaîne des premiers chiffres, nous utilisons next
.
Autres règles de validation :
-
Les méthodes de type "String" : Bien sûr, vous pouvez utiliser d'autres méthodes de chaîne comme 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 plusieurs manières différentes de l'exécuter. L'une d'entre elles 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 chiffres :
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 de la base de données de l'UE. operator
module.
-
Existence d'un chemin :
Ici, on peut utiliser pathlib
et sa bibliothèque Path.exists
mé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 à la fonction itertools.repeat
. Cela peut être combiné avec la fourniture d'une valeur par défaut à l'option next
fonction :
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 tenir compte de ces simples erreurs, nous pouvons prétraiter les données d'entrée en appliquant la méthode suivante str.lower
y str.strip
méthodes. Par exemple, pour 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 effectuant un composition des fonctions . Par exemple, en utilisant celui de 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 de règles de validation :
Pour un cas simple, par exemple, lorsque le programme demande un âge compris entre 1 et 120, on peut simplement ajouter un autre fichier 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 réalisant un conjonction logique . Dans l'exemple suivant, j'utiliserai une version toute prête de 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 d'échec, j'ai bien peur qu'il n'y ait pas d'autre solution. joli de manière fonctionnelle. Ou, du moins, je n'en ai pas trouvé.
16 votes
Je pense qu'il y a un bug dans l'un de vos commentaires, il devrait se lire comme suit
#note: Python 2.7 users should damn-well get their act together and update
:-)