Ответ С.Лотта самый лучший. Но это было слишком долго, чтобы просто добавить к его комментарию, поэтому я разместил его здесь. В любом случае, именно так я и думаю об assert, в основном это простой способ сделать #ifdef DEBUG.
В любом случае, есть две мысли о проверке ввода. Вы можете сделать это у цели или у источника.
Выполнение этого на цели находится внутри кода:
def sqrt(x):
if x<0:
raise ValueError, 'sqrt requires positive numbers'
root = <do stuff>
return root
def some_func(x):
y = float(raw_input('Type a number:'))
try:
print 'Square root is %f'%sqrt(y)
except ValueError:
# User did not type valid input
print '%f must be a positive number!'%y
Теперь, у этого есть много преимуществ. Вероятно, парень, который написал sqrt, знает больше всего о том, какие допустимые значения для его алгоритма. Выше я не знаю, является ли значение, полученное от пользователя, действительным или нет. Кто-то должен это проверить, и имеет смысл сделать это в коде, который больше всего знает о том, что действительно - сам алгоритм sqrt.
Однако, есть потеря производительности. Представьте себе код, подобный этому:
def sqrt(x):
if x<=0:
raise ValueError, 'sqrt requires positive numbers'
root = <do stuff>
return root
def some_func(maxx=100000):
all_sqrts = [sqrt(x) for x in range(maxx)]
i = sqrt(-1.0)
return(all_sqrts)
Теперь эта функция будет вызывать sqrt 100 раз. И каждый раз sqrt будет проверять, является ли значение> = 0. Но мы уже знаем , что оно допустимо из-за того, как мы генерируем эти числа - эти дополнительные действительные проверки просто теряют время выполнения. Разве не было бы хорошо избавиться от них? И затем есть один, который бросит ValueError, и поэтому мы поймаем его и поймем, что допустили ошибку. Я пишу свою программу, опираясь на подфункцию, чтобы проверить меня, и поэтому я просто беспокоюсь о восстановлении, когда оно не работает.
Вторая школа мысли заключается в том, что вместо целевой функции, проверяющей входные данные, вы добавляете ограничения к определению и требует от вызывающего абонента убедиться, что он вызывает действительные данные. Функция обещает, что с хорошими данными она вернет то, что говорит ее контракт. Это позволяет избежать всех этих проверок, потому что вызывающая сторона знает гораздо больше о данных, которые она отправляет, чем о целевой функции, откуда она взята и какие ограничения она имеет по своей природе. Конечным результатом этого являются контракты кода и подобные структуры, но изначально это было просто по соглашению, то есть в дизайне, как в комментарии ниже:
# This function valid if x > 0
def sqrt(x):
root = <do stuff>
return root
def long_function(maxx=100000):
# This is a valid function call - every x i pass to sqrt is valid
sqrtlist1 = [sqrt(x) for x in range(maxx)]
# This one is a program error - calling function with incorrect arguments
# But one that can't be statically determined
# It will throw an exception somewhere in the sqrt code above
i = sqrt(-1.0)
Конечно, ошибки случаются, и контракт может быть нарушен. Но пока результат примерно одинаков - в обоих случаях, если я вызову sqrt (-1.0), я получу исключение внутри самого кода sqrt, смогу пройти по стеку исключений и выяснить, где моя ошибка.
Однако, есть гораздо более коварные случаи ... предположим, например, что мой код генерирует индекс списка, сохраняет его, позже просматривает индекс списка, извлекает значение и выполняет некоторую обработку. и скажем, мы получили список -1 случайно. все эти шаги могут фактически завершиться без каких-либо ошибок, но у нас есть неверные данные в конце теста, и мы не знаем, почему.
Так зачем утверждать? Было бы неплохо иметь что-то, с чем мы могли бы получить отладочную информацию ближе к ошибке, пока мы тестируем и проверяем наши контракты. Это почти то же самое, что и первая форма - в конце концов, она делает то же самое сравнение, но синтаксически более аккуратна и немного более специализирована для проверки контракта. Дополнительным преимуществом является то, что, если вы достаточно уверены, что ваша программа работает, и оптимизируете ее и ищете более высокую производительность по сравнению с возможностью отладки, все эти теперь избыточные проверки могут быть удалены.