python validation loops python-3.x user-input

python - Pedirle al usuario una entrada hasta que den una respuesta válida



validation loops (14)

¿Por qué haría un while True y luego saldría de este bucle mientras que también puede poner sus requisitos en la declaración while ya que todo lo que quiere es parar una vez que tenga la edad?

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

Esto daría lugar a lo siguiente:

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.

esto funcionará ya que la edad nunca tendrá un valor que no tenga sentido y el código sigue la lógica de su "proceso de negocio"

Estoy escribiendo un programa que debe aceptar la entrada del usuario.

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

Esto funciona como se espera si el usuario ingresa datos sensibles.

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

Pero si cometen un error, entonces se estrella:

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

En lugar de estrellarme, me gustaría que intentara obtener la información nuevamente. Me gusta esto:

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!

¿Cómo puedo lograr esto? ¿Y si también quisiera rechazar valores como -1 , que es un int válido, pero sin sentido en este contexto?


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

f=lambda age: (age.isdigit() and ((int(age)>=18 and "Can vote" ) or "Cannot vote")) or / f(raw_input("invalid input. Try again/nPlease enter your age: ")) print f(raw_input("Please enter your age: "))

PS Este código es para python 2.x y se puede exportar a 3.x cambiando las funciones raw_input e print.


Esto continuará pidiéndole al usuario que ingrese el número hasta que ingrese un número válido:

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


La forma más sencilla de lograr esto sería poner el método de input en un bucle while. Use continue cuando tenga mala entrada y salga del ciclo cuando esté satisfecho.

Cuando su entrada puede generar una excepción

Utilice try and catch 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 tus propias reglas de validación

Si desea rechazar valores que Python pueda 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 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 colocar este código en una función, de modo 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

Puedes 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: print(template.format(" or ".join((", ".join(map(str, range_[:-1])), str(range_[-1]))))) else: return ui

Con usos como:

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

Trampas comunes y por qué debe evitarlas

El uso redundante de declaraciones de input redundantes

Este método funciona, pero generalmente se considera 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 método while True , pero viola el principio de No repetirte a ti mismo del desarrollo de software. Esto aumenta la probabilidad de errores en su sistema. ¿Qué raw_input si desea realizar una raw_input de raw_input a 2.7 cambiando la input a raw_input , pero accidentalmente cambiamos solo la primera input anterior? Es un SyntaxError está esperando a suceder.

La recursión soplará tu pila

Si acaba de enterarse de la recursión, puede tener la tentación de usarlo en get_non_negative_int para poder deshacerse del bucle 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 las veces suficientes, el script terminará con un RuntimeError: maximum recursion depth exceeded . Puedes pensar que "ningún tonto cometerá 1000 errores seguidos", ¡pero estás subestimando el ingenio de los tontos!


Mientras que un bloque try / except funcionará, una forma mucho más rápida y limpia de realizar esta tarea sería usar 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.")


Para editar su código y corregir el error:

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


Por lo tanto, estuve jugando con algo similar a esto recientemente, y se me ocurrió la siguiente solución, que utiliza una forma de obtener información que rechaza la basura, incluso antes de que se verifique de alguna manera lógica.

read_single_keypress() cortesía https://.com/a/6599441/4532996

def read_single_keypress() -> str: """Waits for a single keypress on stdin. -- from :: https://.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()

Puedes encontrar el módulo completo here .

Ejemplo:

$ ./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! $ _

Tenga en cuenta que la naturaleza de esta implementación es que cierra la entrada estándar tan pronto como se lee algo que no es un dígito. No presioné Enter después de a , pero necesitaba hacerlo después de los números.

Podría combinar esto con la función thismany() en el mismo módulo para permitir solo, digamos, tres dígitos.


Prueba este: -

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'')


Puede escribir una lógica más general para permitir al usuario ingresar solo un número específico de veces, ya que el mismo caso de uso surge en muchas aplicaciones del mundo real.

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.


Puede hacer que la instrucción de entrada sea un ciclo verdadero mientras que pide repetidamente la entrada de los usuarios y luego interrumpa ese ciclo si el usuario ingresa la respuesta que desea. Y puede usar bloques try y except para manejar respuestas inválidas.

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 es solo para que si el usuario ingresa una cadena en lugar de un entero, el programa no devolverá "No puedes votar en los Estados Unidos".


Una solución más para usar la validación de entrada utilizando un ValidationError personalizado y una validación de rango (opcional) para entradas de enteros:

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

Uso:

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)

Salida:

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


Use la frase "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 de nuevo, y así sucesivamente. En el ejemplo he intentado responder verdaderamente a tu pregunta. Si suponemos que nuestra edad es entre 1 y 150, se acepta el valor de entrada, de lo contrario es un valor incorrecto. Para terminar el programa, el usuario puede usar la tecla 0 e ingresarlo como un valor.

Nota: Lee los comentarios encima del código.

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


Utilice try catch con nunca terminar mientras loop. Para verificar si hay una cadena en blanco, use la instrucción IF para verificar si la cadena está vacía.

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'')


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