Какую валидацию ввода я должен выполнять над моими функциями/методами python?
Мне интересно, сколько людей на передней панели делают в Python, которые они пишут.
Вот несколько примеров простых функций:
def factorial(num):
"""Computes the factorial of num."""
def isPalindrome(inputStr):
"""Tests to see if inputStr is the same backwards and forwards."""
def sum(nums):
"""Same as the built-in sum()... computes the sum of all the numbers passed in."""
Насколько тщательно вы проверяете входные значения перед началом вычислений и как вы выполняете проверку? Вы бросаете какое-то частное исключение, если ввод неисправен (например, BadInputException, определенный в том же модуле)? Вы только начинаете свой расчет и вычисляете, что в какой-то момент будет генерироваться исключение, если бы были переданы плохие данные (например, "asd" для факториала)?
Когда переданное значение должно быть контейнером, вы проверяете не только контейнер, но и все значения внутри него?
Как насчет таких ситуаций, как factorial, где то, что передавалось, может быть конвертировано в int (например, float), но при этом вы можете потерять точность?
Ответы
Ответ 1
Для вычислений, таких как сумма, факториал и т.д., проверки встроенных типов питонов будут выполнены. Вычисления приведут к тому, что upp вызовет добавить, mul и т.д. Для типов, и, если они сломаются, они все равно будут выкидывать правильное исключение. Соблюдая свои собственные проверки, вы можете недействить в противном случае рабочий ввод.
Ответ 2
I assert
что абсолютно необходимо.
Важно: что абсолютно необходимо. Некоторые люди перепробовали вещи.
def factorial(num):
assert int(num)
assert num > 0
Не совсем правильно. долгое время также является юридической возможностью.
def factorial(num):
assert type(num) in ( int, long )
assert num > 0
Лучше, но все же не идеально. Многие типы Python (например, рациональные числа или числовые объекты) также могут работать в хорошей факториальной функции. Трудно утверждать, что объект имеет базовые целочисленные свойства, не будучи слишком конкретным и устраняя будущие неопытные классы из соображений.
Я никогда не определяю уникальные исключения для отдельных функций. Я определяю уникальное исключение для значимого модуля или пакета. Обычно, однако, просто класс Error
или что-то подобное. Таким образом, приложение говорит except somelibrary.Error,e:
, которое касается всего, что вам нужно знать. Мелкозернистые исключения становятся суетливыми и глупыми.
Я никогда этого не делал, но я вижу места, где это может понадобиться.
assert all( type(i) in (int,long) for i in someList )
Как правило, обычные проверки типа Python работают нормально. Они находят почти все исключительные ситуации, которые имеют значение почти все время. Когда что-то не соответствует типу, Python вызывает TypeError, который всегда указывает на правильную строку кода.
BTW. Я добавляю только утверждения во время разработки, если я абсолютно уверен, что функция будет злоупотреблять. Я иногда добавляю утверждения позже, когда у меня есть unit test, который не работает неясным образом.
Ответ 3
Я пытаюсь написать docstring, указав, какой тип параметра ожидается и принят, и я не проверяю его явно в моих функциях.
Если кто-то хочет использовать мою функцию с любым другим типом, его ответственность за проверку того, что его тип эмулирует один, я принимаю достаточно хорошо. Может быть, ваш факториал можно использовать с каким-то обычным длинным типом, чтобы получить то, о чем вы бы не подумали? Или, может быть, ваша сумма может использоваться для конкатенации строк? Почему вы должны запрещать это путем проверки типа? Это не C, так или иначе.
Ответ 4
Я в основном пытаюсь преобразовать переменную в то, что она должна быть, и пропустить или выбросить соответствующее исключение, если это не сработает.
def factorial(num):
"""Computes the factorial of num."""
try:
num = int(num)
except ValueError, e:
print e
else:
...
Ответ 5
Это зависит от того, что я пишу, и как получается выход. Python не имеет публичной/частной защиты других OO-языков. Вместо этого существуют соглашения. Например, внешний код должен вызывать только методы объектов, которые не имеют префикса подчеркиванием.
Поэтому, если я пишу модуль, я бы проверял все, что не было создано из моего собственного кода, то есть любые вызовы общедоступных методов/функций. Иногда, если я знаю, что проверка является дорогостоящей, я делаю ее togglable с kwarg:
def publicly_accessible_function(arg1, validate=False):
if validate:
do_validation(arg1)
do_work
Внутренние методы могут выполнять валидацию с помощью assert, который может быть полностью отключен, когда код выходит из разработки и в производство.
Ответ 6
Я почти никогда не применяю какие-либо проверки, если не думаю, что есть вероятность, что кто-то может подумать, что они могут передать какой-то Х, который принесет совершенно сумасшедшие результаты.
В другой раз я проверяю, когда я принимаю несколько типов для аргумента, например функцию, которая принимает список, может принимать произвольный объект и просто переносить его в список (если он еще не является списком). Поэтому в этом случае я проверяю тип - не для того, чтобы обеспечить что-либо - только потому, что я хочу, чтобы функция была гибкой в том, как она используется.
Ответ 7
Постарайтесь проверить, нет ли у вас отказоустойчивого модульного теста.
Также рассмотрим EAFP"... Это путь Python!
Ответ 8
Немного о перспективах того, как справляется другой язык, может добавить некоторую ценность. Для Perl я помню, используя этот модуль - http://search.cpan.org/dist/Params-Validate/, который выгружает много параметров для проверки разработчика. Я искал что-то подобное в python и наткнулся на это: http://www.voidspace.org.uk/python/validate.html Я не пробовал. Но я предполагаю, что стремление к стандартному способу проверки параметров во всей кодовой базе приводит к предварительной настройке ожиданий проверки параметров по всей команде.