La forma más sencilla de lograr esto es poner el input
método en un ciclo while. Úselo continue
cuando obtenga una entrada incorrecta y break
fuera del ciclo cuando esté satisfecho.
Cuando su entrada puede generar una excepción
Use try
yexcept
para detectar cuándo el usuario ingresa datos que no se pueden analizar.
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.")
Implementando sus propias reglas de validación
Si desea rechazar valores que Python puede analizar con éxito, puede agregar su propia lógica de validación.
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
Combinación de manejo de excepciones y validación personalizada
Ambas técnicas anteriores se pueden combinar en un solo bucle.
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.")
Encapsulando todo en una función
Si necesita pedirle a su usuario muchos valores diferentes, puede ser útil poner este código en una función, para que no tenga que volver a escribirlo cada vez.
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: ")
Poniendolo todo junto
Puede ampliar esta idea para hacer una función de entrada muy genérica:
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 uso como:
age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))
Errores comunes y por qué debería evitarlos
El uso redundante de input
declaraciones redundantes
Este método funciona pero generalmente se considera un estilo pobre:
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): ")
Puede parecer atractivo inicialmente porque es más corto que el while True
método, pero viola el principio de no repetirse del desarrollo de software. Esto aumenta la probabilidad de errores en su sistema. ¿Qué sucede si desea retroceder a 2.7 al cambiar input
a raw_input
, pero cambiar accidentalmente solo el primero de input
arriba? Es SyntaxError
solo esperar que suceda.
La recursión volará tu pila
Si acaba de enterarse de la recursividad, puede tener la tentación de usarla get_non_negative_int
para poder deshacerse del 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
Esto parece funcionar bien la mayor parte del tiempo, pero si el usuario ingresa datos no válidos suficientes veces, el script terminará con un RuntimeError: maximum recursion depth exceeded
. Puedes pensar que "ningún tonto cometería 1000 errores seguidos", ¡pero estás subestimando el ingenio de los tontos!
input
por ciclo y el ciclo se volverá muy corto, pero la condición podría ser bastante larga ...¿Por qué harías un
while True
y luego saldrías de este ciclo mientras también puedes poner tus requisitos en la declaración while ya que todo lo que quieres es parar una vez que tienes la edad?Esto resultaría en lo siguiente:
esto funcionará ya que la edad nunca tendrá un valor que no tendrá sentido y el código sigue la lógica de su "proceso comercial"
fuente
Aunque la respuesta aceptada es asombrosa. También me gustaría compartir un truco rápido para este problema. (Esto también se ocupa del problema de la edad negativa).
PD Este código es para python 3.x.
fuente
def
en su lugar.def f(age):
es mucho más claro quef = lambda age:
Entonces, estaba jugando con algo similar a esto recientemente, y se me ocurrió la siguiente solución, que utiliza una forma de obtener entradas que rechazan la basura, incluso antes de que se verifique de manera lógica.
read_single_keypress()
cortesía https://stackoverflow.com/a/6599441/4532996Puede encontrar el módulo completo aquí .
Ejemplo:
Tenga en cuenta que la naturaleza de esta implementación es que cierra stdin tan pronto como se lee algo que no es un dígito. No presioné enter después
a
, pero necesitaba después de los números.Podría fusionar esto con la
thismany()
función en el mismo módulo para permitir solo, digamos, tres dígitos.fuente
Enfoque funcional o "¡ mira mamá sin bucles! ":
o si desea tener un mensaje de "entrada incorrecta" separado de una solicitud de entrada como en otras respuestas:
¿Como funciona?
itertools.chain
yitertools.repeat
creará un iterador que producirá cadenas"Enter a number: "
una vez y"Not a number! Try again: "
un número infinito de veces:replies = map(input, prompts)
- aquímap
aplicará todas lasprompts
cadenas del paso anterior a lainput
función. P.ej:filter
ystr.isdigit
filtramos aquellas cadenas que contienen solo dígitos: Y para obtener solo la primera cadena de solo dígitos que usamosnext
.Otras reglas de validación:
Métodos de cadena: por supuesto, puede usar otros métodos de cadena como
str.isalpha
obtener solo cadenas alfabéticas ostr.isupper
solo mayúsculas. Ver documentos para la lista completa.Prueba de membresía:
hay varias formas diferentes de realizarla. Uno de ellos es mediante el
__contains__
método:Comparación de números:
Existen métodos de comparación útiles que podemos usar aquí. Por ejemplo, para
__lt__
(<
):O, si no le gusta usar los métodos dunder (dunder = double-subrayado), siempre puede definir su propia función o usar las del
operator
módulo.Existencia de ruta:
aquí se puede usar la
pathlib
biblioteca y suPath.exists
método:Número limitado de intentos:
Si no desea torturar a un usuario preguntándole algo un número infinito de veces, puede especificar un límite en una llamada de
itertools.repeat
. Esto se puede combinar con proporcionar un valor predeterminado a lanext
función:Preprocesamiento de datos de entrada:
A veces no queremos rechazar una entrada si el usuario la suministró accidentalmente EN MAYÚSCULAS o con un espacio al principio o al final de la cadena. Para tener en cuenta estos errores simples, podemos preprocesar los datos de entrada aplicando
str.lower
ystr.strip
métodos. Por ejemplo, para el caso de prueba de membresía, el código se verá así:En el caso de que tenga muchas funciones para usar para el preprocesamiento, puede ser más fácil usar una función que realice una composición de funciones . Por ejemplo, usando el de aquí :
Combinación de reglas de validación:
Para un caso simple, por ejemplo, cuando el programa solicita una edad entre 1 y 120, uno puede agregar otro
filter
:Pero en el caso de que haya muchas reglas, es mejor implementar una función que realice una conjunción lógica . En el siguiente ejemplo, usaré uno listo desde aquí :
Desafortunadamente, si alguien necesita un mensaje personalizado para cada caso fallido, me temo que no hay una manera bastante funcional. O, al menos, no pude encontrar uno.
fuente
Usando Click :
Click es una biblioteca para interfaces de línea de comandos y proporciona funcionalidad para solicitar una respuesta válida de un usuario.
Ejemplo simple:
Tenga en cuenta cómo convirtió el valor de cadena en un flotante automáticamente.
Comprobando si un valor está dentro de un rango:
Se proporcionan diferentes tipos personalizados . Para obtener un número en un rango específico podemos usar
IntRange
:También podemos especificar solo uno de los límites,
min
omax
:Prueba de membresía:
Usando
click.Choice
tipo. Por defecto, esta comprobación distingue entre mayúsculas y minúsculas.Trabajando con rutas y archivos:
Usando un
click.Path
tipo podemos verificar las rutas existentes y también resolverlas:La lectura y escritura de archivos se puede hacer de la siguiente manera
click.File
:Otros ejemplos:
Confirmación de contraseña:
Valores predeterminados:
En este caso, simplemente presionando Enter(o cualquier tecla que use) sin ingresar un valor, le dará uno predeterminado:
fuente
fuente
Sobre la base de las excelentes sugerencias de Daniel Q y Patrick Artner, aquí hay una solución aún más generalizada.
Opté por explícito
if
yraise
declaraciones en lugar de unassert
, porque la comprobación de afirmación puede estar desactivada, mientras que la validación siempre debe estar activada para proporcionar solidez.Esto puede usarse para obtener diferentes tipos de entrada, con diferentes condiciones de validación. Por ejemplo:
O, para responder la pregunta original:
fuente
Prueba este: -
fuente
Si bien a
try
/except
block funcionará, sería una forma mucho más rápida y limpia de lograr esta tareastr.isdigit()
.fuente
¡Buena pregunta! Puede probar el siguiente código para esto. =)
Este código usa ast.literal_eval () para encontrar el tipo de datos de la entrada (
age
). Luego sigue el siguiente algoritmo:Aquí está el código.
fuente
Siempre puede aplicar una lógica simple if-else y agregar una
if
lógica más a su código junto con unfor
bucle.Este será un baño infinito y se le pedirá que ingrese la edad, indefinidamente.
fuente
Puede escribir una lógica más general para permitir que el usuario ingrese solo un número específico de veces, ya que el mismo caso de uso surge en muchas aplicaciones del mundo real.
fuente
Puede hacer que la declaración de entrada sea un ciclo True verdadero para que solicite repetidamente la entrada de los usuarios y luego rompa ese ciclo si el usuario ingresa la respuesta que desea. Y puede usar los bloques try y except para manejar respuestas no válidas.
La variable var es solo para que si el usuario ingresa una cadena en lugar de un entero, el programa no devolverá "No puede votar en los Estados Unidos".
fuente
Use la instrucción "while" hasta que el usuario ingrese un valor verdadero y si el valor de entrada no es un número o es un valor nulo, omítalo e intente preguntar nuevamente y así sucesivamente. Por ejemplo, traté de responder verdaderamente tu pregunta. Si suponemos que nuestra edad está entre 1 y 150, entonces se acepta el valor de entrada, de lo contrario, es un valor incorrecto. Para finalizar el programa, el usuario puede usar la tecla 0 e ingresarla como valor.
fuente
Una solución más para usar la validación de entrada usando una
ValidationError
validación de rango personalizada y (opcional) para entradas enteras:Uso:
Salida:
fuente
Aquí hay una solución más limpia y generalizada que evita los bloques repetitivos if / else: escriba una función que tome pares (Error, solicitud de error) en un diccionario y realice todas sus comprobaciones de valores con aserciones.
Uso:
fuente
Entrada persistente del usuario utilizando la función recursiva :
Cuerda
Entero
y finalmente, el requisito de la pregunta:
fuente
La solución simple sería:
Explicación del código anterior: para una edad válida, debe ser positiva y no debe ser superior a la edad física normal, por ejemplo, la edad máxima es 120.
Luego, podemos pedirle al usuario la edad y si la entrada de edad es negativa o más de 120, consideramos que es una entrada no válida y le pedimos al usuario que intente nuevamente.
Una vez que se ingresa la entrada válida, realizamos una verificación (usando una declaración anidada if-else) si la edad es> = 18 o viceversa e imprimimos un mensaje si el usuario es elegible para votar
fuente
tome la entrada como cadena y use isdigit () para verificar que la entrada solo tenga dígitos, no esté vacía, no puede ser -ve
fuente