На этом шаге мы рассмотрим, в чем заключается это предостережение.
Самое большое предостережение по поводу использования утверждений в Python состоит в том, что утверждения могут быть глобально отключены переключателями командной строки -O и -OO, а также переменной окружения PYTHONOPTIMIZE в СPython.
Это превращает любую инструкцию assert в нулевую операцию: утверждения assert просто компилируются и вычисляться не будут, это означает, что ни одно из условных выражений не будет выполнено.
Это преднамеренное проектное решение, которое используется схожим образом во многих других языках программирования. В качестве побочного эффекта оно приводит к тому, что становится чрезвычайно опасно использовать инструкции assert в виде быстрого и легкого способа проверки входных данных.
Поясним: если в вашей программе утверждения assert используются для проверки того, содержит ли аргумент функции "неправильное" или неожиданное значение, то это решение может быстро обернуться против вас и привести к ошибкам или дырам с точки зрения безопасности.
Давайте взглянем на простой пример, который демонстрирует эту проблему. И снова представьте, что вы создаете приложение Python с интернет-магазином. Где-то среди программного кода вашего приложения есть функция, которая удаляет товар по запросу пользователя.
Поскольку вы только что узнали об assert, вам не терпится применить их в своем коде, и вы пишете следующую реализацию:
def delete_product(prod_id, user): assert user.is_admin(), 'Здесь должен быть администратор' assert store.has_product(prod_id), 'Неизвестный товар' store. get_product(prod_id).delete()
Приглядитесь поближе к функции delete_product(). Итак, что же произойдет, если инструкции assert будут отключены?
В этом примере трехстрочной функции есть две серьезные проблемы, и они вызваны неправильным использованием инструкций assert:
Каким образом можно избежать этих проблем? Ответ таков: никогда не использовать утверждения assert для выполнения валидации данных. Вместо этого можно выполнять проверку обычными инструкциями if и при необходимости вызывать исключения валидации данных, как показано ниже:
def delete_product(product_id, user): if not user.is_admin(): raise AuthError('Для удаления необходимы права администратора') if not store.has_product(product_id): raise VaiueError('Идентификатор неизвестного товара') store.get_product(product_id).delete()
Этот обновленный пример также обладает тем преимуществом, что вместо того, чтобы вызывать неопределенные исключения AssertionError, он теперь вызывает семантически правильные исключения, а именно ValueError или AuthError (которые мы должны были определить сами).
На следующем шаге мы рассмотрим второе предостережение.