Понимание обратной трассировки Python
Оглавление
- Что такое обратная трассировка Python?
- Как вы читаете обратную трассировку Python?
- Каковы некоторые распространенные методы обратной трассировки в Python?
- Как вы регистрируете обратную трассировку?
- Заключение
Смотрите сейчас, к этому уроку прилагается соответствующий видеокурс, созданный командой Real Python. Просмотрите его вместе с письменным руководством, чтобы углубить свое понимание: Как извлечь максимальную пользу из обратной трассировки на Python
Python выводит сообщение обратной трассировки, когда в вашем коде возникает исключение. Результаты обратной трассировки могут быть немного ошеломляющими, если вы видите их впервые или не знаете, о чем они говорят. Но обратная трассировка Python содержит огромное количество информации, которая может помочь вам диагностировать и устранить причину возникновения исключения в вашем коде. Понимание того, какую информацию предоставляет обратная трассировка на Python, жизненно важно для того, чтобы стать лучшим программистом на Python.
К концу этого урока вы сможете:
- Разберитесь со следующей трассировкой, которую вы увидите
- Распознайте некоторые наиболее распространенные обратные трассировки
- Успешно зарегистрируйте обратную трассировку, продолжая обрабатывать исключение
Бесплатный бонус: Нажмите здесь, чтобы получить нашу бесплатную шпаргалку по Python, которая знакомит вас с основами Python 3, такими как работа с данными типы, словари, списки и функции Python.
Что такое обратная трассировка Python?
Обратная трассировка - это отчет, содержащий вызовы функций, выполненные в вашем коде в определенный момент. Обратные трассировки известны под многими названиями, включая трассировка стека, обратная трассировка стека, обратная трассировка и, возможно, другие. В Python используется термин обратная трассировка.
Когда в результате выполнения вашей программы возникнет исключение, Python выведет текущую обратную трассировку, чтобы помочь вам понять, что пошло не так. Ниже приведен пример, иллюстрирующий эту ситуацию:
# example.py def greet(someone): print('Hello, ' + someon) greet('Chad')предварительно> кодовый блок>Здесь
greet()вызывается с параметромsomeone. Однако вgreet()это имя переменной не используется. Вместо этого оно было написано с ошибкой какsomeonв вызовеprint().Примечание: В этом руководстве предполагается, что вы разбираетесь в исключениях Python. Если вы не знакомы с этим языком или просто хотите освежить его в памяти, то вам следует ознакомиться с Исключениями Python: Введение.
Когда вы запустите эту программу, вы получите следующий результат отслеживания:
$ python example.py Traceback (most recent call last): File "/path/to/example.py", line 4, in <module> greet('Chad') File "/path/to/example.py", line 2, in greet print('Hello, ' + someon) NameError: name 'someon' is not definedпредварительно> кодовый блок>В этом выводе обратной трассировки содержится вся информация, необходимая для диагностики проблемы. В последней строке вывода обратной трассировки указывается, какой тип исключения был вызван, а также некоторая соответствующая информация об этом исключении. В предыдущих строках обратной трассировки указан код, который привел к возникновению исключения.
В приведенной выше обратной трассировке исключением был
NameError, что означает, что существует ссылка на некоторое имя (переменную, функцию, класс), которое не было определено. В этом случае имя, на которое ссылается ссылка, являетсяsomeon.В последней строке в этом случае содержится достаточно информации, чтобы помочь вам устранить проблему. Поиск по коду имени
someon, которое содержит ошибку в написании, укажет вам правильное направление. Однако часто ваш код намного сложнее.Как вы читаете обратную трассировку Python?
Обратная трассировка Python содержит много полезной информации, когда вы пытаетесь определить причину возникновения исключения в вашем коде. В этом разделе вы познакомитесь с различными способами обратной трассировки, чтобы понять различные фрагменты информации, содержащиеся в обратной трассировке.
Обзор обратной трассировки Python
В каждой обратной трассировке Python есть несколько важных разделов. На диаграмме ниже показаны различные части:
![]()
В Python лучше всего читать обратную трассировку снизу вверх:
Синее поле: Последняя строка обратной трассировки - это строка сообщения об ошибке. Он содержит имя исключения, которое было вызвано.
Зеленое поле: После названия исключения следует сообщение об ошибке. Это сообщение обычно содержит полезную информацию для понимания причины возникновения исключения.
Желтая вставка: Далее по списку отслеживания расположены различные вызовы функций, которые перемещаются снизу вверх, от самых последних к наименее последним. Эти вызовы представлены записями в две строки для каждого вызова. Первая строка каждого вызова содержит такую информацию, как имя файла, номер строки и название модуля, которые указывают, где можно найти код.
Красное подчеркивание: Вторая строка для этих вызовов содержит фактический код, который был выполнен.
Существует несколько различий между выводом обратной трассировки при выполнении кода в командной строке и при выполнении кода в REPL. Ниже приведен тот же код из предыдущего раздела, выполненный в REPL, и результирующий результат обратной трассировки:
>>> def greet(someone): ... print('Hello, ' + someon) ... >>> greet('Chad') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in greet NameError: name 'someon' is not definedпредварительно> кодовый блок>Обратите внимание, что вместо имен файлов вы получаете
"<stdin>". Это имеет смысл, поскольку вы вводили код с помощью стандартного ввода. Кроме того, выполненные строки кода не отображаются в обратной трассировке.Примечание: Если вы привыкли видеть трассировку стека в других языках программирования, то вы заметите существенную разницу в том, как выглядит обратная трассировка Python в сравнении. В большинстве других языков исключение выводится вверху, а затем идет сверху вниз, от самых последних вызовов к наименее последним.
Об этом уже говорилось, но просто повторю, что обратная трассировка Python должна читаться снизу вверх. Это очень полезно, поскольку результаты обратной трассировки распечатываются, и ваш терминал (или любое другое место, где вы читаете результаты обратной трассировки) обычно оказывается в нижней части выходных данных, что дает вам идеальное место для начала чтения результатов обратной трассировки.
Конкретное пошаговое руководство по обратной трассировке
Просмотр некоторых конкретных результатов обратной трассировки поможет вам лучше понять и увидеть, какую информацию даст вам обратная трассировка.
Приведенный ниже код используется в следующих примерах для иллюстрации информации, которую дает вам обратная трассировка Python:
# greetings.py def who_to_greet(person): return person if person else input('Greet who? ') def greet(someone, greeting='Hello'): print(greeting + ', ' + who_to_greet(someone)) def greet_many(people): for person in people: try: greet(person) except Exception: print('hi, ' + person)предварительно> кодовый блок>Здесь
who_to_greet()принимает значениеpersonи либо возвращает его, либо запрашивает значение для возврата вместо него.Затем
greet()принимает имя для приветствия,someoneи необязательное значениеgreetingи вызываетprint().who_to_greet()также вызывается с переданным значениемsomeone.Наконец,
greet_many()выполнит итерацию по спискуpeopleи вызоветgreet(). Если при вызовеgreet()возникает исключение, то выводится простое приветствие для резервного копирования.В этом коде нет ошибок, которые могли бы привести к возникновению исключения, при условии правильного ввода данных.
Если вы добавите вызов
greet()в нижнюю частьgreetings.pyи укажете аргумент ключевого слова, который он не ожидает (например,greet('Chad', greting='Yo')), то вы получите следующую обратную трассировку:$ python example.py Traceback (most recent call last): File "/path/to/greetings.py", line 19, in <module> greet('Chad', greting='Yo') TypeError: greet() got an unexpected keyword argument 'greting'предварительно> кодовый блок>Еще раз повторю, что с обратной трассировкой на Python лучше всего работать в обратном направлении, продвигаясь по результатам. Начиная с последней строки обратной трассировки, вы можете видеть, что исключением был
TypeError. Сообщения, которые следуют за типом исключения, все после двоеточия, дают вам полезную информацию. В нем говорится, чтоgreet()был вызван с аргументом ключевого слова, которого он не ожидал. Вам также будет присвоено неизвестное имя аргумента:greting.Двигаясь вверх, вы можете увидеть строку, которая привела к возникновению исключения. В данном случае это вызов
greet(), который мы добавили в нижнюю часть таблицы.greetings.py.В следующей строке указан путь к файлу, в котором существует код, номер строки этого файла, в котором можно найти код, и в каком модуле он находится. В данном случае, поскольку наш код не использует никаких других модулей Python, мы просто видим здесь
<module>, что означает, что это файл, который выполняется.Используя другой файл и другие входные данные, вы можете увидеть, что обратная трассировка действительно указывает вам правильное направление для поиска проблемы. Если вы продолжаете в том же духе, удалите вызывающий ошибку
greet()вызов из нижней частиgreetings.pyи добавьте в свой каталог следующий файл:# example.py from greetings import greet greet(1)предварительно> кодовый блок>Здесь вы настроили другой файл Python, который импортирует ваш предыдущий модуль,
greetings.py, и используетеgreet()из него. Вот что произойдет, если вы сейчас побежитеexample.py:$ python example.py Traceback (most recent call last): File "/path/to/example.py", line 3, in <module> greet(1) File "/path/to/greetings.py", line 5, in greet print(greeting + ', ' + who_to_greet(someone)) TypeError: must be str, not intпредварительно> кодовый блок>В этом случае снова возникает исключение
TypeError, но на этот раз сообщение немного менее полезно. Это говорит вам о том, что где-то в коде ожидалось, что он будет работать со строкой, но было задано целое число.Двигаясь вверх, вы увидите строку кода, которая была выполнена. Затем файл и номер строки кода. Однако на этот раз вместо
<module>мы получаем имя выполнявшейся функции,greet().Переходя к следующей выполняемой строке кода, мы видим, что наш проблемный вызов
greet()передается целым числом.Иногда после возникновения исключения другой фрагмент кода перехватывает это исключение и также приводит к возникновению исключения. В таких ситуациях Python выводит все обратные трассировки исключений в том порядке, в котором они были получены, и снова завершается обратным отслеживанием самого последнего исключения raise.
Поскольку это может немного сбить с толку, вот пример. Добавьте вызов
greet_many()в нижней частиgreetings.py:# greetings.py ... greet_many(['Chad', 'Dan', 1])предварительно> кодовый блок>В результате этого должны быть напечатаны приветствия для всех трех пользователей. Однако, если вы запустите этот код, вы увидите пример вывода нескольких сообщений обратной трассировки:
$ python greetings.py Hello, Chad Hello, Dan Traceback (most recent call last): File "greetings.py", line 10, in greet_many greet(person) File "greetings.py", line 5, in greet print(greeting + ', ' + who_to_greet(someone)) TypeError: must be str, not int During handling of the above exception, another exception occurred: Traceback (most recent call last): File "greetings.py", line 14, in <module> greet_many(['Chad', 'Dan', 1]) File "greetings.py", line 12, in greet_many print('hi, ' + person) TypeError: must be str, not intпредварительно> кодовый блок>Обратите внимание на выделенную строку, начинающуюся с
During handlingв приведенном выше выводе. В промежутках между всеми отслеживаниями вы увидите эту строку. Его сообщение предельно ясно: пока ваш код пытался обработать предыдущее исключение, было вызвано другое исключение.Примечание: В Python 3 была добавлена функция отображения трассировки предыдущих исключений. В Python 2 вы получите только обратную трассировку последнего исключения.
Вы уже сталкивались с предыдущим исключением, когда вы вызывали
greet()с целым числом. Поскольку мы добавили1в список людей для приветствия, мы можем ожидать того же результата. Однако функцияgreet_many()заключает вызовgreet()в блокtryиexcept. На всякий случай, еслиgreet()приведет к возникновению исключения,greet_many()хочет напечатать приветствие по умолчанию.Здесь повторяется соответствующая часть
greetings.py:def greet_many(people): for person in people: try: greet(person) except Exception: print('hi, ' + person)предварительно> кодовый блок>Таким образом, когда
greet()приводит кTypeErrorиз-за неправильного ввода целого числа,greet_many()обрабатывает это исключение и пытается напечатать простое приветствие. Здесь код завершается другим, похожим исключением. Он все еще пытается добавить строку и целое число.Просмотр всех выходных данных обратной трассировки может помочь вам понять, что может быть истинной причиной исключения. Иногда, когда вы видите, что возникло окончательное исключение, и его результирующую трассировку, вы все еще не можете понять, в чем проблема. В таких случаях переход к предыдущим исключениям обычно дает вам лучшее представление о первопричине.
Каковы некоторые распространенные методы обратной трассировки в Python?
Знание того, как считывать обратную трассировку на Python, когда ваша программа генерирует исключение, может быть очень полезным при программировании, но знание некоторых наиболее распространенных способов обратной трассировки также может ускорить ваш процесс.
Ниже приведены некоторые распространенные исключения, с которыми вы можете столкнуться, причины, по которым они возникают, и что они означают, а также информация, которую вы можете найти в их обратных ссылках.
AttributeError
AttributeErrorвозникает при попытке доступа к атрибуту объекта, для которого этот атрибут не определен. В документации Python указано, когда возникает это исключение:Вызывается при сбое ссылки на атрибут или присвоении. (Источник)
Вот пример создания
AttributeError:>>> an_int = 1 >>> an_int.an_attribute Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'int' object has no attribute 'an_attribute'предварительно> кодовый блок>Строка сообщения об ошибке для
AttributeErrorсообщает вам, что для определенного типа объекта, в данном случаеint, недоступен атрибут, в данном случаеan_attribute. ОтображениеAttributeErrorв строке сообщения об ошибке может помочь вам быстро определить, к какому атрибуту вы пытались получить доступ и куда обратиться, чтобы это исправить.В большинстве случаев получение этого исключения указывает на то, что вы, вероятно, работаете с объектом не того типа, который вы ожидали:
>>> a_list = (1, 2) >>> a_list.append(3) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'tuple' object has no attribute 'append'предварительно> кодовый блок>В приведенном выше примере вы могли бы ожидать, что
a_listбудет иметь типlist,, который имеет метод с именем.append(). Когда вы получаете исключениеAttributeErrorи видите, что оно было вызвано при попытке вызвать.append(), это говорит вам о том, что вы, вероятно, имеете дело не с тем типом объекта, который ожидали.Часто это происходит, когда вы ожидаете, что объект, возвращаемый из вызова функции или метода, будет иметь определенный тип, а в итоге получаете объект типа
None. В этом случае в строке сообщения об ошибке будет написано,AttributeError: 'NoneType' object has no attribute 'append'.
ImportError
ImportErrorвызывается, когда что-то идет не так с инструкцией import. Вы получите это исключение или его подклассModuleNotFoundError, если модуль, который вы пытаетесь импортировать, не может быть найден или если вы пытаетесь импортировать что-либо из модуля, которого в модуле нет. Документация на Python определяет, когда возникает это исключение:Вызывается, когда у инструкции import возникают проблемы при попытке загрузить модуль. Также вызывается, когда "из списка" в
from ... importимеет имя, которое невозможно найти. (Источник)Вот пример создания
ImportErrorиModuleNotFoundError:>>> import asdf Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named 'asdf' >>> from collections import asdf Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: cannot import name 'asdf'предварительно> кодовый блок>В приведенном выше примере вы можете видеть, что попытка импортировать несуществующий модуль,
asdf, приводит к появлениюModuleNotFoundError. При попытке импортировать что-либо, чего не существует,asdf, из модуля, который существует,collections, это приводит к появлениюImportError. Строки сообщений об ошибках в нижней части результатов отслеживания сообщают вам, какой элемент не удалось импортировать,asdfв обоих случаях.
IndexErrorЗначение
IndexErrorвозникает, когда вы пытаетесь получить индекс из последовательности, напримерlistили atuple, и индекс не найден в последовательности. Документация на Python определяет, когда возникает это исключение:Вызывается, когда индекс последовательности находится вне диапазона. (Источник)
Вот пример, который поднимает вопрос
IndexError:>>> a_list = ['a', 'b'] >>> a_list[3] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of rangeпредварительно> кодовый блок>Строка сообщения об ошибке для
IndexErrorне содержит достаточной информации. Вы можете видеть, что у вас есть ссылка на последовательность, которая равнаout of range, и что это за тип последовательности, в данном случаеlist. Этой информации в сочетании с остальной частью обратной трассировки обычно бывает достаточно, чтобы помочь вам быстро определить, как устранить проблему.
KeyErrorАналогично
IndexError,KeyErrorвызывается при попытке доступа к ключу, которого нет в отображении, обычно этоdict. Думайте об этом как оIndexError, но для словарей. В документации Python указано, когда возникает это исключение:Вызывается, когда ключ сопоставления (словаря) не найден в наборе существующих ключей. (Источник)
Вот пример создания
KeyError:>>> a_dict['b'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'b'предварительно> кодовый блок>В строке сообщения об ошибке для
KeyErrorуказан ключ, который не удалось найти. Это не так уж много, но в сочетании с остальной частью обратной трассировки обычно достаточно, чтобы устранить проблему.Для более подробного изучения
KeyError, ознакомьтесь с Исключениями Python KeyError и способами их обработки.
NameError
NameErrorвозникает, когда вы ссылаетесь на переменную, модуль, класс, функцию или какое-либо другое имя, которое не было определено в вашем коде. В документации Python указано, когда возникает это исключение:Вызывается, когда локальное или глобальное имя не найдено. (Источник)
В приведенном ниже коде
greet()принимает параметрperson. Но в самой функции этот параметр указан с ошибкой вpersn:>>> def greet(person): ... print(f'Hello, {persn}') >>> greet('World') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in greet NameError: name 'persn' is not definedпредварительно> кодовый блок>В строке сообщения об ошибке обратной трассировки
NameErrorуказано имя, которое отсутствует. В приведенном выше примере это переменная или параметр функции, переданный с ошибкой.Также будет задан параметр
NameError, если вы ввели его с ошибкой:>>> def greet(persn): ... print(f'Hello, {person}') >>> greet('World') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in greet NameError: name 'person' is not definedпредварительно> кодовый блок>Здесь может показаться, что вы не сделали ничего плохого. Последняя строка, на которую была сделана ссылка в обратной трассировке, выглядит хорошо. Если вы окажетесь в такой ситуации, то вам нужно будет просмотреть свой код, чтобы найти, где используется и определяется переменная
person. Здесь вы можете быстро увидеть, что в названии параметра была допущена ошибка.
SyntaxError
SyntaxErrorвозникает, когда в вашем коде используется неправильный синтаксис Python. В документации Python указано, когда возникает это исключение:Вызывается, когда анализатор обнаруживает синтаксическую ошибку. (Источник)
Ниже показано, что проблема заключается в отсутствии двоеточия, которое должно быть в конце строки определения функции. В Python REPL эта синтаксическая ошибка возникает сразу после нажатия enter:
>>> def greet(person) File "<stdin>", line 1 def greet(person) ^ SyntaxError: invalid syntaxпредварительно> кодовый блок>Строка сообщения об ошибке в
SyntaxErrorсообщает вам только о том, что возникла проблема с синтаксисом вашего кода. При просмотре приведенных выше строк вы увидите строку с проблемой и, как правило,^(курсор), указывающий на проблемное место. Здесь двоеточие отсутствует в инструкции функцииdef.Кроме того, при трассировке
SyntaxErrorобычная первая строкаTraceback (most recent call last):отсутствует. Это происходит потому, чтоSyntaxErrorвызывается, когда Python пытается проанализировать ваш код, и строки на самом деле не выполняются.
TypeError
TypeErrorвызывается, когда ваш код пытается что-то сделать с объектом, который не может этого сделать, например, пытается добавить строку к целому числу или вызываетlen()для объекта, длина которого не указана.не определено. Документация на Python определяет, когда возникает это исключение:Вызывается, когда операция или функция применяется к объекту неподходящего типа. (Источник)
Ниже приведены несколько примеров возникновения
TypeError:>>> 1 + '1' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'int' and 'str' >>> '1' + 1 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: must be str, not int >>> len(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: object of type 'int' has no len()предварительно> кодовый блок>Все приведенные выше примеры появления
TypeErrorприводят к появлению строки сообщения об ошибке с разными сообщениями. Каждый из них довольно хорошо информирует вас о том, что не так.В первых двух примерах сделана попытка объединить строки и целые числа. Однако они немного отличаются друг от друга:
- Первый пытается добавить
strкint.- Второй пытается добавить
intкstr.Строки сообщения об ошибке отражают эти различия.
В последнем примере предпринята попытка вызвать
len()изint. В строке сообщения об ошибке сообщается, что это невозможно сделать с помощьюint.
ValueErrorЗначение
ValueErrorвызывается, когда значение объекта неверно. Вы можете рассматривать это какIndexError, который возникает из-за того, что значение индекса не находится в диапазоне последовательности, толькоValueErrorдля более общего случая. Документация на Python определяет, когда возникает это исключение:Возникает, когда операция или функция получает аргумент, который имеет правильный тип, но неподходящее значение, и ситуация не описывается более точным исключением, таким как
IndexError. (Источник)Вот два примера возникновения
ValueError:>>> a, b, c = [1, 2] Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: not enough values to unpack (expected 3, got 2) >>> a, b = [1, 2, 3] Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: too many values to unpack (expected 2)предварительно> кодовый блок>Строка сообщения об ошибке
ValueErrorв этих примерах точно указывает, в чем проблема со значениями:
В первом примере вы пытаетесь распаковать слишком много значений. В строке сообщения об ошибке даже сообщается, что вы ожидали распаковать 3 значения, но получили 2 значения.
Во втором примере проблема заключается в том, что вы получаете слишком много значений и недостаточно переменных для их распаковки.
Как вы регистрируете обратную трассировку?
Получение исключения и его последующая трассировка на Python означают, что вам нужно решить, что с этим делать. Обычно исправление кода - это первый шаг, но иногда проблема заключается в неожиданном или неправильном вводе данных. Хотя в вашем коде полезно предусмотреть такие ситуации, иногда также имеет смысл отключить или скрыть исключение, регистрируя обратную трассировку и выполняя что-то еще.
Вот более реальный пример кода, который должен отключить некоторые обратные трассировки на Python. В этом примере используется библиотека
requests. Вы можете узнать больше об этом в Библиотеке запросов Python (руководство):# urlcaller.py import sys import requests response = requests.get(sys.argv[1]) print(response.status_code, response.content)предварительно> кодовый блок>Этот код работает хорошо. Когда вы запустите этот скрипт, указав ему URL-адрес в качестве аргумента командной строки , он вызовет URL-адрес, а затем напечатает код состояния HTTP и содержимое ответа. Это работает даже в том случае, если в ответе был статус HTTP error:
$ python urlcaller.py https://httpbin.org/status/200 200 b'' $ python urlcaller.py https://httpbin.org/status/500 500 b''предварительно> кодовый блок>Однако иногда URL-адрес, указанный вашему скрипту для извлечения, не существует, или хост-сервер не работает. В таких случаях этот скрипт теперь генерирует неперехваченное исключение
ConnectionErrorи выводит сообщение обратной трассировки:$ python urlcaller.py http://thisurlprobablydoesntexist.com ... During handling of the above exception, another exception occurred: Traceback (most recent call last): File "urlcaller.py", line 5, in <module> response = requests.get(sys.argv[1]) File "/path/to/requests/api.py", line 75, in get return request('get', url, params=params, **kwargs) File "/path/to/requests/api.py", line 60, in request return session.request(method=method, url=url, **kwargs) File "/path/to/requests/sessions.py", line 533, in request resp = self.send(prep, **send_kwargs) File "/path/to/requests/sessions.py", line 646, in send r = adapter.send(request, **kwargs) File "/path/to/requests/adapters.py", line 516, in send raise ConnectionError(e, request=request) requests.exceptions.ConnectionError: HTTPConnectionPool(host='thisurlprobablydoesntexist.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7faf9d671860>: Failed to establish a new connection: [Errno -2] Name or service not known',))предварительно> кодовый блок>Обратная трассировка Python здесь может быть очень долгой, поскольку возникает множество других исключений, что в конечном итоге приводит к тому, что
ConnectionErrorвызывается самимrequests. Если вы поднимете окончательную трассировку исключений, вы увидите, что вся проблема началась в нашем коде со строки 5 изurlcaller.py.Если вы заключите строку-нарушительницу в блок
tryиexcept, перехват соответствующего исключения позволит вашему скрипту продолжить работу с другими входными данными :# urlcaller.py ... try: response = requests.get(sys.argv[1]) except requests.exceptions.ConnectionError: print(-1, 'Connection Error') else: print(response.status_code, response.content)предварительно> кодовый блок>В приведенном выше коде используется предложение
elseс блокамиtryиexcept. Если вы не знакомы с этой функцией Python, ознакомьтесь с разделом, посвященнымelseпредложению в Исключениях Python: Введение.Теперь, когда вы запустите скрипт с URL-адресом, который приведет к появлению
ConnectionError, вы получите-1для кода состояния и содержимогоConnection Error:$ python urlcaller.py http://thisurlprobablydoesntexist.com -1 Connection Errorпредварительно> кодовый блок>Это отлично работает. Однако в большинстве реальных систем вы не хотите просто отключать исключение и последующую трассировку, но хотите зарегистрировать обратную трассировку. Ведение журнала обратной трассировки позволяет вам лучше понять, что происходит не так в ваших программах.
Примечание: Чтобы узнать больше о системе ведения журнала в Python, ознакомьтесь с Ведение журнала в Python.
Вы можете зарегистрировать обратную трассировку в скрипте, импортировав
loggingпакет, получив логгер и вызвав.exception()для этого логгера вexceptчасть блокаtryиexcept. Ваш окончательный сценарий должен выглядеть примерно так:# urlcaller.py import logging import sys import requests logger = logging.getLogger(__name__) try: response = requests.get(sys.argv[1]) except requests.exceptions.ConnectionError as e: logger.exception() print(-1, 'Connection Error') else: print(response.status_code, response.content)предварительно> кодовый блок>Теперь, когда вы запускаете скрипт для проблемного URL-адреса, он выводит ожидаемые
-1иConnection Error, но также регистрирует обратную трассировку:$ python urlcaller.py http://thisurlprobablydoesntexist.com ... File "/path/to/requests/adapters.py", line 516, in send raise ConnectionError(e, request=request) requests.exceptions.ConnectionError: HTTPConnectionPool(host='thisurlprobablydoesntexist.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7faf9d671860>: Failed to establish a new connection: [Errno -2] Name or service not known',)) -1 Connection Errorпредварительно> кодовый блок>По умолчанию Python отправляет лог-сообщения со стандартной ошибкой (
stderr). Похоже, что мы вообще не отключили вывод трассировки. Однако, если вы вызовете его снова, перенаправляяstderr, вы увидите, что система ведения журнала работает, и мы можем сохранить наши журналы на потом:$ python urlcaller.py http://thisurlprobablydoesntexist.com 2> my-logs.log -1 Connection Errorпредварительно> кодовый блок>Заключение
Обратная трассировка на Python содержит полезную информацию, которая может помочь вам найти, что происходит не так в вашем коде на Python. Эти обратные трассировки могут показаться немного пугающими, но если вы разберетесь в них и поймете, что они пытаются вам показать, они могут оказаться очень полезными. Построчный просмотр нескольких записей обратной связи поможет вам лучше понять содержащуюся в них информацию и извлечь из них максимальную пользу.
Получение результатов обратной трассировки Python при запуске вашего кода - это возможность улучшить ваш код. Это один из способов, с помощью которого Python пытается помочь вам.
Теперь, когда вы знаете, как читать результаты обратной трассировки на Python, вам будет полезно узнать больше о некоторых инструментах и методах диагностики проблем, о которых вам сообщают результаты обратной трассировки. Встроенный в Python
<статус завершения article-slug="python-traceback" class="btn-group mb-0" data-api-article-bookmark-url="/api/v1/articles/python-traceback/bookmark/" статус завершения data-api-article-url="/api/v1/articles/python-обратная трассировка/завершение_статуса/"> статус завершения> <кнопка поделиться bluesky-text="Интересная статья на #Python от @realpython.com :" email-body="Ознакомьтесь с этой статьей о Python:%0A%0 О том, как понять обратную трассировку Python" email-subject="Статья о Python для вас" twitter-text="Интересная статья о Python от @realpython:" url="https://realpython.com/python-traceback /" url-title="Понимание обратной трассировки Python"> кнопка поделиться>tracebackмодуль можно использовать для работы с обратными трассировками и проверки их результатов. Модульtracebackможет быть полезен, когда вам нужно извлечь больше пользы из результатов обратной трассировки. Также было бы полезно узнать больше о некоторых методах отладки вашего кода на Python и способах отладки в режиме ожидания.Смотрите сейчас, к этому уроку прилагается соответствующий видеокурс, созданный командой Real Python. Просмотрите его вместе с письменным руководством, чтобы углубить свое понимание: Как извлечь максимальную пользу из обратной трассировки на Python
Back to Top
