Python assert что это
№35 Инструкция assert / для начинающих
Инструкции assert в Python — это булевы выражения, которые проверяют, является ли условие истинным ( True ). Они определяют факты (утверждения) в программе. Assertion — это проверка, которую можно включить, а затем выключить, завершив тестирование программы.
Возьмем простой пример функции деления. Можно быть уверенным в том, что делитель не должен быть нолем. Это и указывается при тестировании. Разберем этот пример позже.
Что такое Assertion (утверждение)
Assertions (утверждения) — это инструкции, которые «утверждают» определенный кейс в программе. В Python они выступают булевыми выражениями, которые проверяют, является ли условие истинным или ложным. Если оно истинно, то программа ничего не делает и переходит к выполнению следующей строчки кода.
Но если оно ложно, то программа останавливается и возвращает ошибку.
Следующий синтаксис — это базовая структура инструкций утверждения в Python.
Если же нужно добавить сообщение для вывода при ложном условии, то синтаксис будет таким.
Это сообщение позволит лучше понять, почему код не сработал.
Пример assert
Если нужно симулировать или выполнить отладку кода, чтобы узнать, что именно происходит на определенном этапе, то «утверждения» в Python отлично для этого подходят.
Именно инструмент отладки останавливает программу, как только возникает какая-то ошибка. Он также показывает, где именно она произошла.
Оператор assert в Python: объяснение на примерах
Оператор assert – это встроенный оператор или ключевое слово в Python, используемое для отладки кода. Это своего рода проверка, которая исследует функциональность вашего кода.
В этой статье мы рассмотрим оператор assert в Python и разберем принципы его работы на нескольких примерах.
Синтаксис
Синтаксис использования оператора assert следующий:
Также можно добавить дополнительное сообщение, которое будет выводиться при ошибке. В таком случае синтаксис assert будет следующий:
Примеры
Чтобы разобраться, как пользоваться оператором assert на практике, давайте обсудим несколько примеров.
В assert мы указали условие, что num2 (делитель) не должен быть равен нулю. Данное условие не выполняется, потому что значение num2 равно нулю. Интерпретатор Python выдает ошибку AssertionError вместе с добавленным нами сообщением «The divisor is zero» («Делитель равен нулю»).
Теперь давайте изменим значение num2 и выполним нашу программу снова. На этот раз утверждение assert истинно, так что в этом случае ничего не произойдет. Ошибка не появляется, вместо этого выполняется следующая строка. Таким образом, на экран выведется результат деления — 1.0.
Теперь давайте разберем другой пример. Напишем условие assert для проверки корректности строки.
Можно привести и альтернативный вариант примера со строкой:
Значение переменной val – hello. Это означает, что условие ложно, и программа выведет ошибку AssertionError с нашим комментарием — «The variable value is not equal to Pythonist».
Заключение
Оператор assert – это встроенный оператор в Python, позволяющий отлаживать код. Этот оператор принимает условие и необязательное сообщение, которое выводится, если условие assert ложно. В этом случае инструкция assert выводит AssertionError. Если условие истинно, то ничего не происходит и выполняется следующая строка кода. В этой статье мы подробно объяснили принцип работы оператора assert и разобрали его на примерах.
Функция assert в Python
В этом руководстве мы узнаем о ключевом слове assert в python. Он помогает нам отлаживать код. Если вы хотите смоделировать свой код, вы можете использовать в своем коде инструкции assert.
Ниже приведена базовая структура:
Вы также можете отправить информацию с оператором assert для лучшего понимания ошибки кода.
Ниже приведен способ отправки сообщения с помощью assert:
Утверждение Assert
Оператор assert в Python принимает условие, которое должно быть true. Если условие true, это означает, что утверждение значения переменной в порядке, тогда программа будет работать исправно, и будут выполнены следующие операторы. Но если условие false (это означает, что в нашем коде есть ошибка), возникает исключение.
Пример функции, которая возвращает частное от двух чисел
Мы хотим написать функцию, которая будет возвращать частное от двух чисел. Вот код:
Если мы запустим приведенный выше код, то результат будет следующим:
В третьей строке приведенного выше кода вы можете увидеть инструкцию assert. В этой строке проверяется, больше ли значение переменной num 2 0 или нет. Если больше нуля, т.е. условие true, то проблем не возникает, и мы получаем результат соответственно.
Но когда мы вызвали функцию Division() со вторым аргументом 0, тогда условие assert – false. Вот почему возникает AssertionError, и выдается сообщение «Divisor не может быть нулевым», которое мы написали в части сообщения.
Пример с заменой переменной
Рассмотрим следующий код, мы пытаемся найти квадратный корень из уравнения, скажем (b2 – 4ac).
Вот как мы можем использовать оператора assert для отладки и поиска ошибок в нашем коде на этапе тестирования. Вы можете узнать больше о тестировании кода, используя модуль unitest.
Assert. Что это?
Assert — это специальная конструкция, позволяющая проверять предположения о значениях произвольных данных в произвольном месте программы. Эта конструкция может автоматически сигнализировать при обнаружении некорректных данных, что обычно приводит к аварийному завершению программы с указанием места обнаружения некорректных данных. Странная, на первый взгляд, конструкция — может завалить программу в самый неподходящий момент. Какой же в ней смысл? Давайте подумаем, что произойдет, если во время исполнения программы в какой-то момент времени некоторые данные программы стали некорректными и мы не «завалили» сразу же программу, а продолжили ее работу, как ни в чем не бывало. Программа может еще долго работать после этого без каких-либо видимых ошибок. А может в любой момент времени в будущем «завалиться» сама по известной только ей причине. Или накачать вам полный винчестер контента с гей-порносайтов. Это называется неопределенное поведение (undefined behavior) и, вопреки расхожему мнению, оно свойственно не только языкам программирования с произвольным доступом к памяти (aka C, C++). Т.к. assert завершает программу сразу же после обнаружения некорректных данных, он позволяет быстро локализировать и исправить баги в программе, которые привели к некорректным данным. Это его основное назначение. Assert’ы доступны во многих языках программирования, включая java, c#, c и python.
Какие виды assert’ов бывают?
Assert’ы позволяют отлавливать ошибки в программах на этапе компиляции либо во время исполнения. Проверки на этапе компиляции не так важны — в большинстве случаев их можно заменить аналогичными проверками во время исполнения программы. Иными словами, assert’ы на этапе компиляции являются ничем иным, как синтаксическим сахаром. Поэтому в дальнейшем под assert’ами будем подразумевать лишь проверки во время исполнения программы.
Важно понимать, что входящие аргументы функции могут быть неявными. Например, при вызове метода класса в функцию неявно передается указатель на объект данного класса (aka this и self). Также функция может обращаться к данным, объявленным в глобальной области видимости, либо к данным из области видимости лексического замыкания. Эти аргументы тоже желательно проверять с помощью assert’ов при входе в функцию.
Если некорректные данные обнаружены на этом этапе, то код данной функции может содержать баги. Пример:
Когда и где стоит использовать assert’ы?
Ответ прост — используйте assert’ы всегда и везде, где они хоть чуточку могут показаться полезными. Ведь они существенно упрощают локализацию багов в коде. Даже проверка результатов выполнения очевидного кода может оказаться полезной при последующем рефакторинге, после которого код может стать не настолько очевидным и в него может запросто закрасться баг. Не бойтесь, что большое количество assert’ов ухудшит ясность кода и замедлит выполнение вашей программы. Assert’ы визуально выделяются из общего кода и несут важную информацию о предположениях, на основе которых работает данный код. Правильно расставленные assert’ы способны заменить большинство комментариев в коде. Большинство языков программирования поддерживают отключение assert’ов либо на этапе компиляции, либо во время выполнения программы, так что они оказывают минимальное влияние на производительность программы. Обычно assert’ы оставляют включенными во время разработки и тестирования программ, но отключают в релиз-версиях программ. Если программа написана в лучших традициях ООП, либо с помощью enterprise методологии, то assert’ы вообще можно не отключать — производительность вряд ли изменится.
Когда можно обойтись без assert’ов?
Понятно, что дублирование assert’ов через каждую строчку кода не сильно улучшит эффективность отлова багов. Не существует единого мнения насчет оптимального количества assert’ов, также как и насчет оптимального количество комментариев в программе. Когда я только узнал про существование assert’ов, мои программы стали содержать 100500 assert’ов, многие из которых многократно дублировали друг друга. С течением времени количество assert’ов в моем коде стало уменьшаться. Следующие правила позволили многократно уменьшить количество assert’ов в моих программах без существенного ухудшения в эффективности отлова багов:
Можно избегать дублирующих проверок входящих аргументов путем размещения их лишь в функциях, непосредственно работающих с данным аргументом. Т.е. если функция foo() не работает с аргументом, а лишь передает его в функцию bar(), то можно опустить проверку этого аргумента в функции foo(), т.к. она продублирована проверкой аргумента в функции bar().
Можно опускать assert’ы на недопустимые значения, которые гарантированно приводят к краху программы в непосредственной близости от данных assert’ов, т.е. если по краху программы можно быстро определить местонахождение бага. К таким assert’ам можно отнести проверки указателя на NULL перед его разыменованием и проверки на нулевое значение делителя перед делением. Еще раз повторюсь — такие проверки можно опускать лишь тогда, когда среда исполнения гарантирует крах программы в данных случаях.
Вполне возможно, что существуют и другие способы, позволяющие уменьшить количество assert’ов без ухудшения эффективности отлова багов. Если вы в курсе этих способов, делитесь ими в комментариях к данному посту.
Когда нельзя использовать assert’ы?
Т.к. assert’ы могут быть удалены на этапе компиляции либо во время исполнения программы, они не должны менять поведение программы. Если в результате удаления assert’а поведение программы может измениться, то это явный признак неправильного использования assert’а. Таким образом, внутри assert’а нельзя вызывать функции, изменяющие состояние программы либо внешнего окружения программы. Например, следующий код неправильно использует assert’ы:
Очевидно, что данные могут оказаться незащищенными при отключенных assert’ах.
Чтобы исправить эту ошибку, нужно сохранять результат выполнения функции во временной переменной, после чего использовать эту переменную внутри assert’а:
Т.к. основное назначение assert’ов — отлов багов (aka ошибки программирования), то они не могут заменить обработку ожидаемых ошибок, которые не являются ошибками программирования. Например:
Если write() возвращает 0, то это вовсе не означает, что в нашей программе есть баг. Если assert’ы в программе будут отключены, то ошибка записи может остаться незамеченной, что впоследствие может привести к печальным результатам. Поэтому assert() тут не подходит. Тут лучше подходит обычная обработка ошибки. Например:
Я программирую на javascript. В нем нет assert’ов. Что мне делать?
В некоторых языках программирования отсутствует явная поддержка assert’ов. При желании они легко могут быть там реализованы, следуя следующему «паттерну проектирования»:
Вообще, assert’ы обычно реализованы в различных фреймворках и библиотеках, предназначенных для автоматизированного тестирования. Иногда они там называются expect’ами. Между автоматизированным тестированием и применением assert’ов есть много общего — обе техники предназначены для быстрого выявления и исправления багов в программах. Но, несмотря на общие черты, автоматизированное тестирование и assert’ы являются не взаимоисключающими, а, скорее всего, взаимодополняющими друг друга. Грамотно расставленные assert’ы упрощают автоматизированное тестирование кода, т.к. тестирующая программа может опустить проверки, дублирующие assert’ы в коде программы. Такие проверки обычно составляют существенную долю всех проверок в тестирующей программе.
Оператор assert и вывод информации о проверках¶
Проверка с помощью оператора assert ¶
можно использовать, чтобы убедиться что ваша функция вернет определенное значение. Если assert упадет, вы сможете увидеть значение, возвращаемое вызванной функцией:
pytest поддерживает отображение значений наиболее распространенных операций, включая вызовы, параметры, сравнения, бинарные и унарные операции (см. Python: примеры отчетов об ошибках pytest ). Это позволяет использовать стандартные конструкции python без шаблонного кода, не теряя при этом информацию.
Однако, если вы укажете в assert текст сообщения об ошибке, например, вот так,
то никакая аналитическая информация выводиться не будет, и в трейсбэке вы увидите просто указанное сообщение об ошибке.
Проверка ожидаемых исключений¶
А если нужно получить доступ к фактической информации об исключении, можно использовать:
Чтобы проверить, что регулярное выражение соответствует строковому представлению исключения (аналогично методу TestCase.assertRaisesRegexp в unittest ), конекст-менеджеру можно передать параметр match :
В случае падения теста pytest выведет вам полезную информацию, например, о том, что исключение не вызвано (no exception) или вызвано неверное исключение (wrong exception).
Проверка ожидаемых предупреждений¶
Использование контекстно-зависимых сравнений¶
pytest выводит подробный анализ контекстно-зависимой информации, когда сталкивается со сравнениями. Например, в результате исполнения этого модуля
будет выведен следующий отчет:
Вывод результатов сравнения для отдельных случаев:
сравнение длинных строк: будут показаны различия
сравнение длинных последовательностей: будет показан индекс первого несоответствия
сравнение словарей: будут показаны различающиеся элементы
Определение собственных сообщений к упавшим assert ¶
Можно добавить свое подробное объяснение, реализовав хук (hook) pytest_assertrepr_compare (см. pytest_assertrepr_compare).
Для примера рассмотрим добавление в файл conftest.py хука, который устанавливает наше сообщение для сравниваемых объектов Foo :
Теперь напишем тестовый модуль:
Запустив тестовый модуль, получим сообщение, которое мы определили в файле conftest.py :
Детальный анализ неудачных проверок (assertion introspection)¶
Детальный анализ упавших проверок достигается переопределением операторов assert перед запуском. Переопределенные assert помещают аналитическую информацию в сообщение о неудачной проверке. pytest переопределяет только тестовые модули, обнаруженные им в процессе сборки (collecting) тестов, поэтому «assert«-ы в поддерживающих модулях, которые сами по себе не являются тестами, переопределены не будут.
Можно вручную включить возможность переопределения assert для импортируемого модуля, вызвав register-assert-rewrite перед его импортом (лучше это сделать в корневом файле«conftest.py«).
Дополнительную информацию можно найти в статье Бенджамина Петерсона: Behind the scenes of pytest’s new assertion rewriting.
Кэширование переопределенных файлов¶
Отключение переопределения assert ¶
На этот случай есть 2 опции:
Отключите переопределение для отдельного модуля, добавив строку PYTEST_DONT_REWRITE в docstring (строковую переменную для документирования модуля).