Chiedere un input all'utente fino a quando non fornisce una risposta valida
Sto scrivendo un programma che accetta un input dall'utente.
#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.")
Il programma funziona come previsto fintanto che l'utente immette dati significativi.
C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!
Ma fallisce se l'utente inserisce dati non validi:
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'
Invece di bloccarsi, vorrei che il programma chiedesse di nuovo l'input. Come questo:
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!
Come posso fare in modo che il programma richieda input validi invece di bloccarsi quando vengono inseriti dati non sensibili?
Come posso rifiutare valori come -1
, che è un valore valido int
, ma senza senso in questo contesto?
Risposte
Il modo più semplice per ottenere ciò è inserire il input
metodo in un ciclo while. Usalo continue
quando ricevi un input sbagliato e break
quando sei soddisfatto.
Quando il tuo contributo potrebbe sollevare un'eccezione
Utilizzare try
eexcept
per rilevare quando l'utente immette dati che non possono essere analizzati.
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.")
Implementazione delle proprie regole di convalida
Se vuoi rifiutare valori che Python può analizzare con successo, puoi aggiungere la tua logica di convalida.
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
Combinazione di gestione delle eccezioni e convalida personalizzata
Entrambe le tecniche di cui sopra possono essere combinate in un unico ciclo.
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.")
Incapsulare tutto in una funzione
Se hai bisogno di chiedere al tuo utente molti valori diversi, potrebbe essere utile inserire questo codice in una funzione, in modo da non doverlo riscrivere ogni volta.
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: ")
Mettere tutto insieme
Puoi estendere questa idea per creare una funzione di input molto generica:
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
Con utilizzi come:
age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))
Errori comuni e perché dovresti evitarli
L'uso ridondante di input
dichiarazioni ridondanti
Questo metodo funziona ma è generalmente considerato uno stile scadente:
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): ")
All'inizio potrebbe sembrare attraente perché è più breve del while True
metodo, ma viola il principio Don't Repeat Yourself dello sviluppo del software. Ciò aumenta la probabilità di bug nel sistema. Cosa succede se si desidera eseguire il backport a 2.7 passando input
a raw_input
, ma modificare accidentalmente solo il primo input
sopra? Sta SyntaxError
solo aspettando che accada.
La ricorsione farà saltare il tuo stack
Se hai appena imparato a conoscere la ricorsione, potresti essere tentato di usarla in get_non_negative_int
modo da poter eliminare il ciclo 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
Questo sembra funzionare bene la maggior parte delle volte, ma se l'utente inserisce dati non validi abbastanza volte, lo script terminerà con un RuntimeError: maximum recursion depth exceeded
. Potresti pensare che "nessuno sciocco commetterebbe 1000 errori di fila", ma stai sottovalutando l'ingenuità degli sciocchi!
Perché dovresti fare un while True
e poi uscire da questo ciclo mentre puoi anche semplicemente inserire i tuoi requisiti nell'istruzione while poiché tutto ciò che vuoi è fermarti una volta raggiunta l'età?
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.")
Ciò comporterebbe quanto segue:
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.
questo funzionerà poiché l'età non avrà mai un valore che non avrà senso e il codice segue la logica del tuo "processo aziendale"
Anche se la risposta accettata è sorprendente. Vorrei anche condividere un rapido trucco per questo problema. (Questo si prende cura anche del problema dell'età negativa.)
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 Questo codice è per python 3.x.
Approccio funzionale o " guarda mamma senza loop! ":
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
o se vuoi avere un messaggio di "input errato" separato da un prompt di input come in altre risposte:
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
Come funziona?
-
Questa combinazione diprompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
itertools.chain
eitertools.repeat
creerà un iteratore che produrrà stringhe"Enter a number: "
una volta e"Not a number! Try again: "
un numero infinito di volte: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)
- quimap
applicheranno tutte leprompts
stringhe del passaggio precedente allainput
funzione. Per esempio: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...
- Usiamo
filter
estr.isdigit
per filtrare quelle stringhe che contengono solo cifre:only_digits = filter(str.isdigit, replies) for reply in only_digits: print(reply)
E per ottenere solo la prima stringa di sole cifre che usiamoEnter 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...
next
.
Altre regole di convalida:
Metodi di stringa: Ovviamente puoi usare altri metodi di stringa come
str.isalpha
ottenere solo stringhe alfabetiche ostr.isupper
solo maiuscole. Vedi i documenti per l'elenco completo.Test di appartenenza:
esistono diversi modi per eseguirlo. Uno di questi è usare il__contains__
metodo: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
Confronto dei numeri:
ci sono metodi di confronto utili che possiamo usare qui. Ad esempio, per__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
Oppure, se non ti piace usare i metodi dunder (dunder = double-underscore), puoi sempre definire la tua funzione o usare quelli del
operator
modulo.Esistenza del percorso:
qui si può usare lapathlib
libreria e il suoPath.exists
metodo: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
Limitazione del numero di tentativi:
Se non vuoi torturare un utente chiedendogli qualcosa un numero infinito di volte, puoi specificare un limite in una chiamata di itertools.repeat
. Questo può essere combinato con la fornitura di un valore predefinito alla next
funzione:
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!
Pre-elaborazione dei dati di input:
A volte non vogliamo rifiutare un input se l'utente lo ha fornito accidentalmente IN MAIUSCOLO o con uno spazio all'inizio o alla fine della stringa. Per tenere conto di questi semplici errori possiamo preelaborare i dati di input applicando str.lower
e str.strip
metodi. Ad esempio, nel caso del test di appartenenza il codice sarà simile a questo:
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
Nel caso in cui si abbiano molte funzioni da utilizzare per la preelaborazione, potrebbe essere più semplice utilizzare una funzione che esegue una composizione di funzioni . Ad esempio, usando quello da qui :
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
Combinazione di regole di convalida:
Per un caso semplice, ad esempio, quando il programma richiede un'età compresa tra 1 e 120 anni, se ne può semplicemente aggiungere un'altra 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)
Ma nel caso in cui ci siano molte regole, è meglio implementare una funzione che esegue una congiunzione logica . Nel seguente esempio ne userò uno già pronto da qui :
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
Sfortunatamente, se qualcuno ha bisogno di un messaggio personalizzato per ogni caso fallito, allora, temo, non esiste un modo abbastanza funzionale. O almeno non sono riuscito a trovarne uno.
Quindi, stavo scherzando con qualcosa di simile a questo di recente, e ho trovato la seguente soluzione, che utilizza un modo per ottenere input che rifiuta la spazzatura, prima ancora che venga controllata in modo logico.
read_single_keypress()
per gentile concessione di 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()
Puoi trovare il modulo completo qui .
Esempio:
$ ./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!
$ _
Si noti che la natura di questa implementazione è che chiude lo stdin non appena viene letto qualcosa che non è una cifra. Non ho premuto invio dopo a
, ma avevo bisogno di dopo i numeri.
Potresti fonderlo con la thismany()
funzione nello stesso modulo per consentire, diciamo, solo tre cifre.
Utilizzando il clic :
Click è una libreria per le interfacce della riga di comando e fornisce funzionalità per chiedere una risposta valida a un utente.
Esempio semplice:
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
Nota come ha convertito automaticamente il valore della stringa in un float.
Verifica se un valore è all'interno di un intervallo:
Sono disponibili diversi tipi personalizzati . Per ottenere un numero in un intervallo specifico possiamo utilizzare 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
Possiamo anche specificare solo uno dei limiti, min
oppure 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 di appartenenza:
Usando il click.Choice
tipo. Per impostazione predefinita, questo controllo fa distinzione tra maiuscole e minuscole.
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
Lavorare con percorsi e file:
Usando un click.Path
tipo possiamo controllare i percorsi esistenti e anche risolverli:
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 lettura e la scrittura di file possono essere eseguite da 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!
Altri esempi:
Conferma password:
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
Valori standard:
In questo caso, semplicemente premendo Enter(o qualunque tasto tu usi) senza inserire un valore, ne otterrai uno predefinito:
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
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."
Basandosi sugli eccellenti suggerimenti di Daniel Q e Patrick Artner, ecco una soluzione ancora più generalizzata.
# 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)
Ho optato per esplicite if
e raise
dichiarazioni invece di assert
, perché il controllo delle asserzioni potrebbe essere disattivato, mentre la convalida dovrebbe essere sempre attiva per fornire robustezza.
Questo può essere utilizzato per ottenere diversi tipi di input, con diverse condizioni di convalida. Per esempio:
# 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!"})
Oppure, per rispondere alla domanda originale:
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.")
Prova questo:-
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')
Sì, sono in ritardo di 6 anni dal 🎉 ma questa domanda merita una risposta più aggiornata.
Separazione degli interessi
Sono un grande fan della filosofia Unix "Fai una cosa e fallo bene" . In questo tipo di problema, è meglio suddividere il problema in
- Chiedi input con
get_input
finché l'input non è corretto. - Convalida in
validator
funzione. È possibile scrivere diversi validatori per diverse query di input.
Chiedere input
Può essere mantenuto semplice come (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)
Esempio
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'
Nota Python 3.8+
In Python 3.8+ potresti usare l'operatore walrus
def get_input(prompt, validator, on_validationerror):
while not validator(value := input(prompt)):
print(on_validationerror)
return value
Mentre un blocco try
/ except
funzionerà, un modo molto più rapido e pulito per eseguire questa operazione sarebbe quello di utilizzare 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.")
Buona domanda! Puoi provare il seguente codice per questo. =)
Questo codice usa ast.literal_eval () per trovare il tipo di dati di input ( age
). Quindi segue il seguente algoritmo:
Chiedere all'utente di inserire il suo
age
.1.1. Se
age
èfloat
oint
tipo di dati:
Controlla se
age>=18
. Seage>=18
, stampa l'output appropriato ed esci.Controlla se
0<age<18
. Se0<age<18
, stampa l'output appropriato ed esci.Se
age<=0
, chiedere all'utente di inserire di nuovo un numero valido per l'età, (ad esempio tornare al passaggio 1.)1.2. Se
age
non èfloat
o ilint
tipo di dati, chiedere all'utente di inserire nuovamente la sua età (ad esempio, tornare al passaggio 1.)
Ecco il codice.
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.")
Puoi sempre applicare una semplice logica if-else e aggiungere un'altra if
logica al tuo codice insieme a un for
ciclo.
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
Questo sarà un bagno infinito e ti verrà chiesto di entrare nell'età, indefinitamente.
Il codice seguente può aiutare.
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='')
Se vuoi avere il massimo di tentativi, ad esempio 3, usa il codice seguente
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='')
Nota: utilizza la ricorsione.
Usa try-tranne per gestire l'errore e ripeterlo di nuovo:
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")