Каков самый "правильный" Pythonic способ проверки пользовательского ввода в Python?
Я использовал следующее:
while True:
stuff = input("Please enter foo: ")
try:
some_test(stuff)
print("Thanks.")
break
except SomeException:
print("Invalid input.")
Я полагаю, что это приятно и читабельно, но я не могу не задаться вопросом, нет ли какой-то встроенной функции или чего-то, что я должен использовать вместо этого.
Не могли бы вы показать больше кода? thefourtheye 12.12.2013
Извините, я случайно отправил, не закончив печатать! henrebotha 12.12.2013
Я думаю, что то, что вы сделали (используя try~except), неплохо, хотя есть и другие способы для той же задачи. Я не слышал о пути Pythonic. Такая задача возникает на всех других языках. GoodGJ 12.12.2013
Полностью зависит от того, что вы подразумеваете под проверкой ввода (номер кредитной карты, IP-адрес, int, float?), и что вы хотите делать, когда происходит сбой проверки. Lukas Graf 12.12.2013
Функция some_test не должна иметь значения. В одной конкретной ситуации, с которой я сейчас имею дело, some_test выглядит следующим образом: with smtplib.SMTP_SSL(host=host, port=port) as server: server.login(user, password) вызывает исключение, если вход не удался. Впрочем, я спрашиваю в целом. henrebotha 12.12.2013
Мне нравятся декораторы, чтобы отделить проверку от остальной обработки ввода.
#!/usr/bin/env python
def repeatOnError(*exceptions):
def checking(function):
def checked(*args, **kwargs):
while True:
try:
result = function(*args, **kwargs)
except exceptions as problem:
print "There was a problem with the input:"
print problem.__class__.__name__
print problem
print "Please repeat!"
else:
return result
return checked
return checking
@repeatOnError(ValueError)
def getNumberOfIterations():
return int(raw_input("Please enter the number of iterations: "))
iterationCounter = getNumberOfIterations()
print "You have chosen", iterationCounter, "iterations."
РЕДАКТИРОВАТЬ:
Декоратор - это более или менее оболочка для существующей функции (или метода). Он берет существующую функцию (обозначенную ниже ее директивы @decorator) и возвращает для нее "замену". Эта замена в нашем случае вызывает исходную функцию в цикле и перехватывает любое возникающее при этом исключение. Если исключения не происходит, он просто возвращает результат исходной функции.
Ответ 2 · рейтинг 3 · James Mills
Самый Pythonic способ выполнить такую проверку "User INput" - перехватить соответствующее исключение.
Пример:
def get_user_input():
while True:
try:
return int(input("Please enter a number: "))
except ValueError:
print("Invalid input. Please try again!")
n = get_user_input()
print("Thanks! You entered: {0:d}".format(n))
Также рекомендуется разрешать исключениям там, где они лежат, и позволять им всплывать, а не скрывать их, чтобы вы могли четко видеть, что происходит не так в Python Traceback.
В этом случае Проверка пользовательского ввода - используйте Duck Typing в Python и перехватите ошибку. то есть: если он действует как воздуховод, это должна быть утка. (Если он действует как int, он должен быть int).
Ответ 3 · eyquem
Немного сложно, но может быть интересно:
import re
from sys import exc_info,excepthook
from traceback import format_exc
def condition1(stuff):
'''
stuff must be the string of an integer'''
try:
i = int(stuff)
return True
except:
return False
def condition2(stuff):
'''
stuff is the string of an integer
but the integer must be in the range(10,30)'''
return int(stuff) in xrange(10,30)
regx = re.compile('assert *\( *([_a-z\d]+)')
while True:
try:
stuff = raw_input("Please enter foo: ")
assert(condition1(stuff))
assert ( condition2(stuff))
print("Thanks.")
break
except AssertionError:
tbs = format_exc(exc_info()[0])
funky = globals()[regx.search(tbs).group(1)]
excepthook(exc_info()[0], funky.func_doc, None)
результат
Please enter foo: g
AssertionError:
stuff must be the string of an integer
Please enter foo: 170
AssertionError:
stuff is the string of an integer
but the integer must be in the range(10,30)
Please enter foo: 15
Thanks.
.
Редактировать
Я нашел способ упростить:
from sys import excepthook
def condition1(stuff):
'''
stuff must be the string of an integer'''
try:
int(stuff)
return True
except:
return False
def another2(stuff):
'''
stuff is the string of an integer
but the integer must be in the range(10,30)'''
return int(stuff) in xrange(10,30)
tup = (condition1,another2)
while True:
try:
stuff = raw_input("Please enter foo: ")
for condition in tup:
assert(condition(stuff))
print("Thanks.")
break
except AssertionError:
excepthook('AssertionError', condition.func_doc, None)