Запрос пользователя для ввода, пока они не дадут действительный ответ
Я пишу программу, которая должна принимать ввод от пользователя.
#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.")
это работает, как ожидалось, если пользователь вводит разумные данные.
C:PythonProjects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!
но если они ошибаются, то он падает:
C:PythonProjects> 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'
вместо сбоя, я хотел бы, чтобы попытаться получить вход снова. Вот так:
C:PythonProjects> 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!
как я могу это сделать? Что, если бы я также хотел отклонить такие значения, как -1
, который является допустимым int
, но бессмысленно в этом контекст?
13 ответов
самый простой способ сделать это было бы поставить input
метод в цикле while. Использовать continue
когда вы получаете плохой вход, и break
выход из цикла, когда вы удовлетворены.
когда ваш ввод может вызвать исключение
использовать try и Catch чтобы определить, когда пользователь вводит данные, которые не могут быть разобраны.
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.")
Реализация Собственных Правил Проверки
если вы хотите отклонить значения что Python может успешно анализировать, вы можете добавить свою собственную логику проверки.
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
объединение обработки исключений и пользовательской проверки
оба вышеуказанных метода можно совместить в один цикл.
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.")
Инкапсулирование всего этого в функцию
Если вам нужно запросить у пользователя много разных значений, может быть полезно поместить этот код в функцию, поэтому вам не нужно перепечатывать его каждый раз время.
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: ")
Складывая Все Это Вместе
вы можете расширить эту идею, чтобы сделать очень общую функцию ввода:
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
С использованием таких как:
age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))
общие подводные камни, и почему вы должны избегать их
избыточное использование избыточного input
заявления
этот метод работает, но обычно считается плохим стилем:
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): ")
это может выглядеть привлекательно изначально, потому что это короче чем while True
метод, но он нарушает не повторяйся принцип разработки программного обеспечения. Это увеличивает вероятность ошибок в вашей системе. Что делать, если вы хотите вернуться к 2.7, изменив input
to raw_input
, но случайно изменить только первый input
выше? Это SyntaxError
просто ждал, чтобы произойти.
Рекурсия Взорвет Ваш Стек
если вы только что узнали о рекурсии, у вас может возникнуть соблазн использовать ее в get_non_negative_int
так вы можете избавиться от цикла 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
это, кажется, работает нормально большую часть времени, но если пользователь вводит недопустимые данные достаточно раз, скрипт завершится с RuntimeError: maximum recursion depth exceeded
. Вы можете подумать ,что "ни один дурак не сделает 1000 ошибок подряд", но вы недооцениваете изобретательность дураков!
почему вы сделали while True
а затем вырваться из этого цикла, пока вы также можете просто поместить свои требования в оператор while, так как все, что вы хотите, это остановиться, как только у вас есть возраст?
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.")
это приведет к следующим:
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.
это будет работать, так как возраст никогда не будет иметь значения, которое не будет иметь смысла, и код следует логике вашего "бизнес-процесса"
хотя принятый ответ удивителен. Я также хотел бы поделиться быстрым взломом для этой проблемы. (Это также решает проблему негативного возраста.)
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: "))
P. S. Это код для Python 2.x и может быть экспортирован в 3.x путем изменения функции raw_input и печати.
Итак, я возился с чем-то похожим на это недавно, и я придумал следующее решение, которое использует способ получения ввода, который отклоняет мусор, прежде чем он даже будет проверен каким-либо логическим способом.
read_single_keypress()
любезность 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()
вы можете найти полный модуль здесь.
пример:
$ ./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!
$ _
обратите внимание, что характер этой реализации закрывает stdin, как только что-то, что не является цифрой, читается. Я не нажал enter после a
, но мне нужно было после чисел.
вы можете объединить это с thismany()
функция в том же модуле, чтобы разрешить только, скажем, три цифры.
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."
попробуйте это:-
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')
чтобы отредактировать код и исправить ошибку:
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")
вы можете написать более общую логику, чтобы позволить пользователю вводить только определенное количество раз, так как один и тот же прецедент возникает во многих реальных приложениях.
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.
Используйте оператор "while", пока пользователь не введет истинное значение, и если входное значение не является числом или нулевым значением, пропустите его и повторите попытку и так далее. В примере я попытался ответить по-настоящему на ваш вопрос. Если мы предположим, что наш возраст находится между 1 и 150, то входное значение принято, Иначе это неправильное значение. Для завершения программы пользователь может использовать ключ 0 и ввести его в качестве значения.
Примечание: читать комментарии в верхней части кода.
# 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.")
а try
/except
блок будет работать, гораздо быстрее и чище способ выполнить эту задачу будет использовать 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.")
вы можете сделать оператор ввода a while True loop, чтобы он неоднократно запрашивал ввод пользователей, а затем разорвать этот цикл, если пользователь вводит ответ, который вы хотите. И вы можете использовать try и except блоки для обработки неверные ответы.
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.")
переменная var такова, что если пользователь вводит строку вместо целого числа, программа не будет возвращать "Вы не можете голосовать в Соединенных Штатах."
используйте try catch с бесконечным циклом while. Чтобы проверить пустую строку, используйте оператор IF, чтобы проверить, пуста ли строка.
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')
это будет продолжать просить пользователя ввести номер, пока они не введут допустимое число:
#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 ")