Лучшей практикой, по-видимому, является использование assert
для условия, которое никогда не должно произойти, если код правильный, и исключения для условия, которое немного необычное, но может произойти (например, когда заканчивается память или пользовательский ввод недействителен, или внешние соединения разорваны). Я понимаю смысл этой практики следующим образом:
assert
будет отключен с флагом интерпретатора -O. Условия, которые могут возникнуть из-за внешних факторов, нельзя молча игнорировать, поэтому утверждать, что это неуместно. OTOH, условия, которые могут возникнуть только в том случае, если мой код неверен, надеюсь, будут устранены с помощью тестирования и отладки, поэтомуassert
в порядке.assert
отговаривает вызывающую сторону от обработки исключения, посколькуAssertionError
обычно интерпретируется как "не поймайте меня, это катастрофический сбой". Кроме того, это слишком общее, чтобы поймать. Это идеально, когда обнаружена ошибка; типичной обработкой для этого будет остановка выполнения и отладка кода. Нехорошо, если это обычное состояние, вызванное внешними причинами.
Предположим, я пишу некоторый код, в котором я гарантирую, что определенный аргумент функции всегда положителен. Если я нахожу его отрицательным, очевидно, я допустил ошибку в коде. Следовательно, я собираюсь assert
утверждать, что аргумент положителен.
Позже кто-то находит эту функцию полезной в другом приложении. Они импортируют его и отправляют на него всевозможные данные. Теперь, с точки зрения моей функции, вполне вероятно получение отрицательного значения; это просто недопустимый пользовательский ввод. Возможно, assert
больше не подходит, и его следует заменить исключением.
Поскольку почти любой код потенциально может быть использован повторно однажды, часто без моего ведома, этот аргумент, кажется, говорит: «никогда не используйте assert
; используйте только исключения». Очевидно, что это не общепринятая практика. Что мне не хватает?
РЕДАКТИРОВАТЬ:
Чтобы быть более конкретным, предположим, что функция вообще не может обрабатывать отрицательный аргумент. Итак, как только аргумент отрицательный, функция выполнит одно из следующих действий:
- создать исключение
- провалить утверждение
- продолжить выполнение, что, вероятно, приведет к неправильному выводу
Я вижу, как было бы хорошо, если бы вызывающая сторона перехватывала отрицательные аргументы. Но если вызовы функции разбросаны по всему коду в десятках мест, это, возможно, наносит ущерб ясности кода из-за многочисленных повторений одной и той же проверки. (Не говоря уже о том, что его можно было случайно забыть.)
assert
для проверки значений извне. Если вы получаете площадь чего-то из какой-то внутренней вспомогательной функции, возможно, стоитassert area >= 0
(в вызывающем коде или рядом со сложной символьной математикой, выполняющей вычисления). - person   schedule 05.04.2012assert x > 0
в начале функции десятками повторений того же самого вне функции. Хуже того, в другой раз при вызове функции кто-то забудет добавитьassert
. - person max   schedule 05.04.2012assert
. Я полагаю, это имелось в виду? - person max   schedule 05.04.2012