Найти ошибку в программе питон

Инструкция assert применяется для автоматического об­наружения ошибок в программах Python. Эта инструкция сделает ваши программы надежнее и проще в отладке.

По своей сути инструкция assert представляет собой средство отладки, которое проверяет условие. Если условие утверждения assert истинно, то ничего не происходит и ваша программа продолжает выпол­няться как обычно. Но если же вычисление условия дает результат ложно, то вызывается исключение AssertionError с необязательным сообщением об ошибке.

Пример использования assert

Предположим, вы создаете интернет-магазин с помощью Python. Вы рабо­таете над добавлением в систему функциональности скидочного купона, и в итоге вы пишете следующую функцию apply_discount() :

def apply_discount(product, discount): price = int(product[‘цена’] * (1.0 — discount)) assert 0 price product[‘цена’] return price

Инструкция assert будет гарантировать, что, независимо от обстоятельств, вычисляемые этой функцией снижен­ные цена не может быть ниже 0 и выше первоначаль­ной цены товара.

Эти ошибки совершает каждый новичок Python / 11 Ошибок которые нужно исправить

Давайте убедимся, что эта функция действительно работает как заду­мано, если вызвать ее, применив допустимую скидку. В этом примере товары в нашем магазине будут представлены в виде простых слова­рей, для демонстрации утверждений assert :

shoes = ‘name’: ‘shoes’, ‘price’: 14999>

Избегая проблем с округлением денежной цены, используйте целое число для представления цены в копейках. Итак, если к этим туфлям мы применим 25 %-ную скидку, то ожидаемо придем к отпускной цене 112,49:

apply_discount(shoes, 0.25) # 112,49

Функция сработала. Теперь попробуем при­менить несколько недопустимых скидок. Например, 200%-ную «скидку», которая вынудит нас отдать деньги покупателю:

>>> apply_discount(shoes, 2.0) Traceback (most recent call last): File «», line 1, in module> apply_discount(prod, 2.0) File «», line 4, in apply_discount assert 0 price product[‘price’] AssertionError
1
2
3
4
5
6
7

Когда пытаемся применить недопустимую скидку, наша программа останавливается с исключением AssertionError . Это происходит потому, что 200 %-ная скидка нарушила условие утверждения assert .

Видно отчет об этом исключении и то, как он указывает на точную строку исходного кода, содержащую вы­звавшее сбой утверждение. Если во время проверки интернет-магазина вы (или другой разработчик в вашей команде) когда-нибудь столкнетесь с одной из таких ошибок, вы легко узнаете, что произошло, просто по­смотрев на отчет об обратной трассировке исключения.

Это значительно ускорит отладку и в дальнейшем сделает ваши про­граммы удобнее в поддержке. В этом и заключается сила assert !

# Почему не применить обычное исключение?

Теперь подумаем, почему в предыдущем примере просто не применить инструкцию if и исключение.

Дело в том, что инструкция assert предназначена для того, чтобы сооб­щать разработчикам о неустранимых ошибках в программе. Инструкция assert не предназначена для того, чтобы сигнализировать об ожидаемых ошибочных условиях, таких как ошибка «Файл не найден», где пользователь может предпринять корректирующие действия или просто попро­бовать еще раз.

Как найти ошибку в коде Работа с отладчиком

Инструкции призваны быть внутренними самопроверками (internal self­checks) вашей программы. Они работают путем объявления неких усло­вий, возникновение которых в вашем исходном коде невозможно. Если одно из таких условий не сохраняется, то это означает, что в программе есть ошибка.

Если ваша программа бездефектна, то эти условия никогда не возникнут. Но если же они возникают, то программа завершится аварийно с исклю­чением AssertionError , говорящим, какое именно «невозможное» усло­вие было вызвано. Это намного упрощает отслеживание и исправление ошибок в ваших программах.

А пока имейте в виду, что инструкция assert — это средство отладки, а не механизм обработки ошибок исполнения программы. Цель использования инструкции assert состоит в том, чтобы позволить разра­ботчикам как можно скорее найти вероятную первопричину ошибки. Если в вашей программе ошибки нет, то исключение AssertionError никогда не должно возникнуть.

Давайте взглянем поближе на другие вещи, которые мы можем делать с инструкцией assert , а затем я покажу две распространенные ловушки, которые встречаются во время ее использования в реальных сценариях.

Прежде чем вы начнете применять какое-то функциональное средство языка, всегда неплохо подробнее познакомиться с тем, как оно практиче­ски реализуется в Python. Поэтому давайте бегло взглянем на синтаксис инструкции assert в соответствии с документацией Python

инструкция_assert ::= «assert» logical_expression [«,» error_message]

  • logical_expression — это условие, которое мы проверяем,
  • error_message (не­обязательное) — это сообщение об ошибке, которое выводится на экран, если утверждение дает сбой.

Во время исполнения программы интерпретатор Python преобразовывает каждую инструкцию assert при­мерно в следующую ниже последовательность инструкций:

if __debug__: if not logical_expression: raise AssertionError(error_message)

В этом фрагменте кода есть две интересные детали.

Перед тем как данное условие инструкции assert будет проверено, про­водится дополнительная проверка глобальной переменной __debug__ . Это встроенный булев флажок, который при нормальных обстоятельствах имеет значение True , — и значение False , если запрашивается оптимиза­ция. Мы поговорим об этом подробнее чуть позже в разделе, посвященном «распространенным ловушкам».

Кроме того, вы можете применить error_message , чтобы передать необязатель­ное сообщение об ошибке, которое будет показано в отчете об обратной трассировке вместе с исключением AssertionError . Это может еще больше упростить отладку. Например, исходный код такого плана:

if cond == ‘x’: do_x() elif cond == ‘y’: do_y() else: assert False, (»’Это никогда не должно произойти, и тем не менее это временами происходит. Сейчас мы пытаемся выяснить причину. Если вы столкнетесь с этим на практике, то просим связаться по электронной почте с dbader. Спасибо!»’)
1
2
3
4
5
6

Читайте также:
Задачи организации на начальной странице программы 1с бухгалтерия 8

Конечно это ужасно, но этот прием определенно допустим и полезен, если в одном из своих приложений вы сталкиваетесь с плава­ющей ошибкой.

# Ловушки assert

Есть два важных предостережения, на которые стоит обратить внимание:

  1. Первое из них связано с внесением в приложения ошибок и рисков, свя­занных с нарушением безопасности.
  2. Второе касается синтаксической причуды, которая облегчает написание бесполезных инструкций assert .

Звучит довольно ужасно (и потенциально таковым и является), поэтому вам, вероятно, следует как минимум просмотреть эти два предостереже­ния хотя бы бегло.

Не используйте инструкции assert для проверки данных!

Самое большое предостережение по поводу использования утверждений в 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 несет в себе опасность. Если утверждения assert отключены в интерпрета­торе Python, то проверка полномочий превращается в нулевую опера­цию. И поэтому теперь любой пользователь может удалять товары. Проверка полномочий вообще не выполняется. В результате повы­шается вероятность того, что может возникнуть проблема, связанная с обеспечением безопасности, и откроется дверь для атак, способных разрушить или серьезно повредить данные в нашем интернет-магазине. Очень плохо.
  • Проверка has_product() пропускается, когда assert отключена. Это означает, что метод get_product() теперь можно вызывать с недо­пустимыми идентификаторами товаров, что может привести к более серьезным ошибкам, — в зависимости от того, как написана наша программа. В худшем случае она может стать началом запуска DoS-атак. Например, если приложение магазина аварийно завершается при по­пытке стороннего лица удалить неизвестный товар, то, скорее всего, это произошло потому, что взломщик смог завалить его недопустимыми запросами на удаление и вызвать сбой в работе сервера.

Каким образом можно избежать этих проблем? Ответ таков: никогда не использовать утверждения assert для выполнения валидации данных. Вместо этого можно выполнять проверку обычными инструкциями if и при необходимости вызывать исключения валидации данных, как по­казано ниже:

def delete_product(product_id, user): if not user.is_admin(): raise AuthError(‘Для удаления необходимы права админа’) if not store.has_product(product_id): raise ValueError(‘Идентификатор неизвестного товара’) store.get_product(product_id).delete()
1
2
3
4
5
6

Этот обновленный пример также обладает тем преимуществом, что вме­сто того, чтобы вызывать неопределенные исключения AssertionError , он теперь вызывает семантически правильные исключения, а имен­но ValueError или AuthError (которые мы должны были определить сами).

Инструкции assert , которые никогда не дают сбоя.

Удивительно легко случайно написать инструкцию assert , которая всегда при вычислении возвращает истину. Вкратце проблема в следующем.

Когда в инструкцию assert в качестве первого аргумента передается кортеж, assert всегда возвращает True и по этой причине выполняется успешно.

Например, это утверждение никогда не будет давать сбой:

assert(1 == 2, ‘Это утверждение должно вызвать сбой’)

Эта ситуация связана с тем, что в Python непустые кортежи всегда явля­ются истинными. Если вы передаете кортеж в инструкцию assert , то это приводит к тому, что условие assert всегда будет истинным, что, в свою очередь, приводит к тому, что вышеупомянутая инструкция assert ста­нет бесполезной, потому что она никогда не сможет дать сбой и вызвать исключение.

По причине такого, в общем-то, не интуитивного поведения относительно легко случайно написать плохие многострочные инструкции assert . На­пример, представьте, что в одном из ваших модуль­ных тестов имеется приведенное ниже утверждение:

assert ( counter == 10, ‘Это должно было сосчитать все элементы’ )

На первый взгляд этот тестовый случай выглядит абсолютно приемле­мым. Однако он никогда не выловит неправильный результат: это ут­верждение assert всегда будет давать истину, независимо от состояния переменной counter . И в чем же тут дело? А в том, что оно подтверждает истинность объекта-кортежа.

Более свежие версии Python 3 для таких сомнительных инструкций assert показывают синтаксическое предупреждение.

Между прочим, именно поэтому всегда следует выполнять быстрый тест при помощи своих модульных тестовых случаев. Прежде чем переходить к написанию следующего, убедитесь, что они действительно не срабатывают.

# Инструкции assert — резюме

Несмотря на данные выше предостережения, я полагаю, что инструкции assert являются мощным инструментом отладки, который зачастую не­достаточно используется разработчиками Python.

Понимание того, как работают инструкции assert и когда их применять, поможет писать программы Python, которые будет легче сопровождать и отлаживать.

Это великолепный навык, который стоит освоить, чтобы прокачать зна­ния Python до более качественного уровня и стать всесторонним питонистом.Это позволит сэкономить бесконечные часы, которые приходится тратить на отладку.

  • Инструкция assert — это средство отладки, которое проверяет условие, выступающее в качестве внутренней самопроверки вашей программы.
  • Инструкции assert должны применяться только для того, чтобы по­могать разработчикам идентифицировать ошибки. Они не являются механизмом обработки ошибок периода исполнения программы.
  • Инструкции assert могут быть глобально отключены в настройках интерпретатора.
Читайте также:
Допишите программу чтобы она выводила результат 01234

Источник: learn4kid-python.firebaseapp.com

Проверка кода Python с помощью PyLint

Область применения:yesVisual StudionoVisual Studio для Mac noVisual Studio Code

Широко распространенное средство PyLint позволяет искать ошибки в коде Python и поощряет правильные методы создания кода Python. Это средство интегрируется в проекты Python для Visual Studio.

Выполнить PyLint

снимок экрана команды PyLint в контекстном меню для проектов Python в обозревателе решений.

В Visual Studio щелкните правой кнопкой мыши проект Python в Обозреватель решений и выберите Python, а затем Выполните PyLint:

При запуске этой команды вы увидите предложение установить PyLint в вашем окружении, если это еще не сделано.

снимок экрана со списком ошибок PyLint.

Предупреждения и ошибки PyLint отображаются в окне Список ошибок :

Дважды щелкнув ошибку, вы перейдете к тому участку исходного кода, в котором она возникла.

В разделе документации по функциям PyLint вы можете найти полный список исходящих сообщений PyLint.

Настройка параметров командной строки PyLint

В разделе документации PyLint, посвященном параметрам командной строки, описывается управление поведением PyLint с помощью файла конфигурации .pylintrc . Этот файл можно разместить в корне проекта Python в Visual Studio или в другом месте в зависимости от того, где нужно применять эти параметры (подробные сведения см. в описании параметров командной строки).

Например, с помощью файла .pylintrc можно отключить предупреждение «отсутствует docstring», представленное на изображении выше. Для этого выполните следующие действия:

    В командной строке перейдите в корневой каталог проекта (где находится файл .pyproj ) и выполните следующую команду, чтобы создать файл конфигурации с заметками:

pylint —generate-rcfile > .pylintrc

Совет Для использования файла .pylintrc из сетевой папки создайте переменную среды с именем PYLINTRC и присвойте ей в качестве значения имя файла в сетевой папке с указанием UNC-пути или буквы подключенного диска. Например, PYLINTRC=\mysharepython.pylintrc .

Источник: learn.microsoft.com

Ошибки в Python — 7 шагов для поиска ошибок в коде Python

Представьте себе такую ситуацию: в пятницу в обед вы получаете уведомление о том, что клиент обнаружил ошибку в вашем программном обеспечении. После того, как вы преодолели свое первоначальное недоверие, вы связываетесь с DevOps, чтобы узнать, что творится с логами для вашего приложения, потому что вы помните, что получили уведомление о том, что они были перемещены.

Оказывается, они находятся там, куда вы не можете добраться, но они находятся в процессе перемещения в веб-приложение, поэтому у вас будет подходящий инструмент для их чтения и поиска, но, конечно, он еще не закончен. Все будет готов лишь через пару дней. Это практически нереальная ситуация, верно? К сожалению, нет.

Логи или сообщения логов часто невозможно найти в тот самый момент, когда они больше всего нужны. Прежде чем мы начнем отслеживать ошибки, следует сделать публичное объявление: проверьте ваши логи, чтобы убедиться, что они на месте и регулярно записывают то, что, по вашему мнению, они должны регистрировать. Удивительно, как все эти вещи куда-то исчезают, когда ты за ними не смотришь.

Итак, вы нашли логи или проверили сообщение клиента, который действительно обнаружил ошибку. Может быть, вы даже думаете, что знаете, где эта самая ошибка спряталась.

Вы немедленно открываете файл, который, по вашему мнению, может быть проблемой, и начинаете в нем ковыряться.

1. Не трогайте пока еще свой код

Взгляните на проблемное место и, возможно, даже выдвиньте гипотезу. Но прежде чем вы начнете разбираться в коде, возьмите тот вызов, который создает ошибку, и превратите его в тест. Это будет интеграционный тест, потому что (хотя у вас уже могут быть догадки) вы еще не знаете точно, в чем проблема.

Убедитесь, что этот тест не пройден. Это важно, потому что иногда тест, который вы делаете, не имитирует прерванный вызов; это особенно верно, если вы используете веб-интерфейс или другой фреймворк, который может запутать тесты. Многие вещи могут храниться в переменных, и, к сожалению, из самого теста не всегда очевидно, какой вызов вы в нем делаете.

2. Напишите неудачный тест

Теперь, когда у вас есть провальный тест или, возможно, тест с ошибкой, пришло время для устранения неполадок. Но прежде чем сделать это, давайте сделаем обзор стека, так как это облегчает поиск неисправностей.

Стек состоит из всех задач, которые вы начали, но не завершили. Итак, если вы будете печь торт и добавлять муку в тесто, то ваш стек будет:

  • Сделать торт;
  • Сделать тесто;
  • Добавить муку.

Вы начали готовить торт, начали готовить жидкое тесто и добавляли муку. Смазывания сковороды нет в списке, так как вы уже закончили это, а приготовления глазури нет в списке, потому что вы еще этого не начали.

Если вы не совсем разобрались в стеке, я настоятельно рекомендую попробовать Python Tutor, где вы можете наблюдать за стеком при выполнении строк кода.

Теперь, если с вашей программой на Python что-то пойдет не так, интерпретатор услужливо выведет для вас стек. Это означает, что независимо от того, что программа делала в данный момент, станет очевидно, что что-то пошло не так, как надо.

3. Всегда проверяйте дно стека в первую очередь

И не только дно стека, где вы можете увидеть, какая именно ошибка у вас произошла, но и последнюю строку стека, где вы чаще всего можете найти проблему. Если нижняя часть не помогает, и ваш код не проверялся уже какое-то время, удивительно, насколько полезным может быть его запуск. Я рекомендую pylint или flake8. Чаще всего именно они указывают на то, где есть ошибка, которую я пропустил.

Читайте также:
Как добавить в загрузочную флешку свои программы

Если ошибка является чем-то неясным, вашим следующим шагом может стать просто Google. Вам повезет больше, если вы не включите информацию, относящуюся только к вашему коду, например, имя переменных, файлов и т. д. Если вы используете Python 3, полезно включить 3 в поисковый запрос; в противном случае решения Python 2 имеют тенденцию доминировать в топе.

Когда-то разработчикам приходилось устранять неполадки без помощи поисковой системы. Это было темное время. Так что воспользуйтесь всеми доступными вам инструментами.

К сожалению, иногда проблема возникала раньше и стала очевидной только во время выполнения строки в нижней части стека.

Пришло время искать стек. Скорее всего, проблема заключается в том, что проблема в вашем коде, а не в ядре Python или даже в сторонних пакетах, поэтому сначала сканируйте стек, ища строки в вашем коде. Кроме того, обычно гораздо проще установить точку прерывания в вашем собственном коде. Вставьте ее в свой код немного дальше вверх по стеку и посмотрите вокруг, чтобы увидеть, что все выглядит, как и должно.

Затем воспользуйтесь помощью Pdb (the Python Debugger).

Найдите в своем коде место, в котором по вашему мнению должен появиться вызов. Вы должны быть в состоянии найти хотя бы одно такое место. Воткните туда pdb.

Отступление

Почему не печатное выражение? Я привык зависеть от печатных выражений. Они все еще иногда пригождаются. Но как только я начал работать со сложными кодами, особенно с сетевыми вызовами, печать стала слишком медленной. Я закончил с печатными заявлениями повсюду, я потерял след, где они были и почему, и все только усложнилось.

Но есть более важная причина использовать pdb. Допустим, вы поместили заявление для печати и обнаружили, что что-то не так – и, должно быть, раньше пошло не так. Но, глядя на функцию, в которую вы помещаете оператор print, вы не представляете, как вы туда попали. Просмотр кода – отличный способ увидеть, куда вы идете, но он ужасен для изучения того, где вы были.

И да, я сделал обзор своей базы кода, ища, где вызывается функция, но это может быть слишком утомительным занятием и не сильно сузить границы поиска с помощью популярной функции. Pdb может быть крайне полезным.

Вы следуете моему совету, вставляете pdb-break и запускаете тест. И он проваливается и снова терпит неудачу, без перерыва вообще. Оставьте свою точку прерывания и запустите тест уже в вашем наборе тестов, который делает что-то очень похожее на неудачный тест.

Если у вас есть приличный набор тестов, вы сможете найти тест, который соответствует тому коду, который, по вашему мнению, должен пройти ваш проваленный тест. Запустите этот тест, и когда он достигнет вашей точки прерывания, сделайте w и посмотрите на стек. Если вы не понимаете, посмотрев в стек, как/где другой вызов сломался, то пройдите на полпути вверх по стеку, найдите некоторую часть кода, которая вам принадлежит, и поместите точку прерывания в этот файл, на одну строку выше той в трассировке стека. Попробуйте еще раз с новым тестом. Продолжайте двигаться вперед и назад, двигаясь вверх по стеку, чтобы выяснить, где ваш вызов сошел с рельс.

4. Поменяйте что-нибудь

Если вы все еще не можете разобраться, попробуйте сделать новый тест, в котором вы слегка изменили что-то. Можете ли вы заставить новый тест работать? Какая разница? Попробуйте изменить что-то еще. После того, как у вас появится тест и, возможно, дополнительные тесты тоже, можно смело начинать что-то менять в своем коде, чтобы посмотреть, сможете ли вы сузить радиус проблемы.

Не забудьте начать устранение неполадок в новых условиях, чтобы вы могли легко отбросить изменения, которые не помогают.

5. Сделайте перерыв

На полном серьезе, когда все происходящее перестает быть забавным испытанием или игрой и начинает становиться действительно разочаровывающим процессом, ваш лучший план действий – абстрагироваться от проблемы. Сделать перерыв. Я настоятельно рекомендую пойти погулять и попытаться подумать о чем-то другом.

6. Записывайте все

Если по возвращению у вас вдруг не появится желание попробовать что-то еще, запишите любую имеющуюся у вас информацию о проблеме. Сюда должно входить:

  • Конкретный вызов, который вызывает проблему;
  • Что именно произошло, включая любые сообщения об ошибках или связанные сообщения журнала;
  • Именно то, что вы ожидали;
  • Что вы сделали до сих пор, чтобы найти проблему и любые подсказки, которые вы обнаружили при устранении неполадок.

Иногда информации будет слишком много, но, поверьте мне, это действительно может помочь. Постарайтесь быть кратким, но полным.

7. Попросите о помощи

Я часто замечаю, что простое записывание всей информации вызывает мысль о том, чего я еще не пробовал. Иногда, конечно, я понимаю, в чем проблема сразу после нажатия кнопки «Отправить». В любом случае, если вы все еще ничего не придумали после того, как все записали, попробуйте отправить кому-нибудь письмо.

Сначала попробуйте коллег или других людей, вовлеченных в ваш проект, а затем переходите к спискам рассылки проекта. Не бойтесь просить о помощи. Большинство людей добры и полезны, и это особенно верно в сообществе Python.

Другие мануалы

  • Преимущества и недостатки бесплатных доменов
  • Синий экран смерти? — Наиболее частые причины популярной ошибки
  • Tripmydream Academy: выбери удаленную работу для себя
  • Как просушить телефон от воды в домашних условиях с несъемным аккумулятором

Источник: overcoder.net

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru