errors.md
1> **Источник:** https://python-all.ru/3.9/tutorial/errors.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 8. Ошибки и исключения89До сих пор мы лишь упоминали сообщения об ошибках, но если вы пробовали примеры, то, скорее всего, уже с ними сталкивались. Существует (как минимум) два различимых вида ошибок: *синтаксические ошибки* и *исключения*.1011## 8.1. Синтаксические ошибки1213Синтаксические ошибки, также известные как ошибки разбора, – пожалуй, самый распространённый вид неполадок, с которыми вы сталкиваетесь, пока учите Python:1415```python16>>> while True print('Hello world')17 File "<stdin>", line 118 while True print('Hello world')19 ^20SyntaxError: invalid syntax21```2223Парсер повторяет проблемную строку и показывает маленькую «стрелку», указывающую на самую раннюю позицию в строке, где была обнаружена ошибка. Ошибка вызвана (или, по крайней мере, обнаружена) элементом *предшествующим* стрелке: в примере ошибка обнаружена у функции [`print()`](https://python-all.ru/3.9/library/functions.html#print), поскольку перед ней отсутствует двоеточие (`':'`). Имя файла и номер строки выводятся, чтобы было понятно, где искать, если входные данные поступили из сценария.2425## 8.2. Исключения2627Даже если оператор или выражение синтаксически верны, при попытке его выполнения может возникнуть ошибка. Ошибки, обнаруженные во время выполнения, называются *исключениями* и не являются безусловно фатальными: вы скоро научитесь обрабатывать их в программах на Python. Однако большинство исключений не обрабатываются программами и приводят к сообщениям об ошибках, как показано ниже:2829```python30>>> 10 * (1/0)31Traceback (most recent call last):32 File "<stdin>", line 1, in <module>33ZeroDivisionError: division by zero34>>> 4 + spam*335Traceback (most recent call last):36 File "<stdin>", line 1, in <module>37NameError: name 'spam' is not defined38>>> '2' + 239Traceback (most recent call last):40 File "<stdin>", line 1, in <module>41TypeError: can only concatenate str (not "int") to str42```4344Последняя строка сообщения об ошибке показывает, что произошло. Исключения бывают разных типов, и тип выводится как часть сообщения: в примере это [`ZeroDivisionError`](https://python-all.ru/3.9/library/exceptions.html#ZeroDivisionError), [`NameError`](https://python-all.ru/3.9/library/exceptions.html#NameError) и [`TypeError`](https://python-all.ru/3.9/library/exceptions.html#TypeError). Строка, выводимая как тип исключения, – это имя встроенного исключения, которое произошло. Это верно для всех встроенных исключений, но не обязательно для определяемых пользователем (хотя это полезное соглашение). Стандартные имена исключений – встроенные идентификаторы (не зарезервированные ключевые слова).4546Остальная часть строки содержит подробности в зависимости от типа исключения и того, что его вызвало.4748Предшествующая часть сообщения об ошибке показывает контекст, в котором произошло исключение, в виде трассировки стека. Обычно она содержит трассировку стека с перечислением строк исходного кода; однако строки, прочитанные из стандартного ввода, не отображаются.4950[Встроенные исключения](https://python-all.ru/3.9/library/exceptions.html#bltin-exceptions) содержит список встроенных исключений и их значение.5152## 8.3. Обработка исключений5354Можно писать программы, обрабатывающие выбранные исключения. В следующем примере показан запрос ввода у пользователя до тех пор, пока не будет введено целое число, но при этом пользователь может прервать программу (с помощью `Control-C` или того, что поддерживает операционная система); обратите внимание, что прерывание пользователем вызывает исключение [`KeyboardInterrupt`](https://python-all.ru/3.9/library/exceptions.html#KeyboardInterrupt).5556```python57>>> while True:58... try:59... x = int(input("Please enter a number: "))60... break61... except ValueError:62... print("Oops! That was no valid number. Try again...")63...64```6566Инструкция [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try) работает следующим образом.6768- Сначала выполняется *try-блок* (инструкции между ключевыми словами [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try) и [`except`](https://python-all.ru/3.9/reference/compound_stmts.html#except)).69- Если исключение не произошло, *except-блок* пропускается, и выполнение инструкции [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try) завершается.70- Если при выполнении блока try возникает исключение, оставшаяся часть блока пропускается. Затем, если его тип совпадает с исключением, указанным после [`except`](https://python-all.ru/3.9/reference/compound_stmts.html#except) ключевого слова, выполняется блок except, и затем выполнение продолжается после оператора [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try).71- Если возникает исключение, которое не соответствует исключению, указанному в блоке except, оно передается внешним операторам [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try); если обработчик не найден, это *необработанное исключение* и выполнение останавливается с сообщением, как показано выше.7273Оператор [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try) может содержать более одного блока except для указания обработчиков разных исключений. Будет выполнен не более одного обработчика. Обработчики обрабатывают только исключения, возникшие в соответствующем блоке try, а не в других обработчиках того же оператора `try`. Блок except может указывать несколько исключений в виде кортежа в скобках, например:7475```python76... except (RuntimeError, TypeError, NameError):77... pass78```7980Класс в блоке [`except`](https://python-all.ru/3.9/reference/compound_stmts.html#except) совместим с исключением, если это тот же класс или его базовый класс (но не наоборот – блок except, содержащий производный класс, несовместим с базовым классом). Например, следующий код выведет B, C, D в таком порядке:8182```python83class B(Exception):84 pass8586class C(B):87 pass8889class D(C):90 pass9192for cls in [B, C, D]:93 try:94 raise cls()95 except D:96 print("D")97 except C:98 print("C")99 except B:100 print("B")101```102103Обратите внимание, что если бы блоки except были переставлены (с `except B` первым), то вывелось бы B, B, B – срабатывает первый подходящий блок except.104105Последний блок except может опускать имена исключений, чтобы служить универсальным обработчиком. Используйте это с особой осторожностью, поскольку легко скрыть настоящую ошибку программирования таким образом! Его также можно использовать для вывода сообщения об ошибке и последующего повторного возбуждения исключения (позволяя вызывающему коду также обработать исключение):106107```python108import sys109110try:111 f = open('myfile.txt')112 s = f.readline()113 i = int(s.strip())114except OSError as err:115 print("OS error: {0}".format(err))116except ValueError:117 print("Could not convert data to an integer.")118except:119 print("Unexpected error:", sys.exc_info()[0])120 raise121```122123Оператор [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try) … [`except`](https://python-all.ru/3.9/reference/compound_stmts.html#except) имеет необязательную *часть else*, которая, если присутствует, должна следовать за всеми блоками except. Она полезна для кода, который должен быть выполнен, если блок try не вызвал исключение. Например:124125```python126for arg in sys.argv[1:]:127 try:128 f = open(arg, 'r')129 except OSError:130 print('cannot open', arg)131 else:132 print(arg, 'has', len(f.readlines()), 'lines')133 f.close()134```135136Использование блока `else` лучше, чем добавление дополнительного кода в блок [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try), поскольку это позволяет избежать случайного перехвата исключения, которое не было возбуждено кодом, защищённым инструкцией `try` … `except`.137138Когда возникает исключение, оно может иметь связанное значение, также известное как *аргумент* исключения. Наличие и тип аргумента зависят от типа исключения.139140Блок except может указывать переменную после имени исключения. Эта переменная связывается с экземпляром исключения, аргументы которого хранятся в `instance.args`. Для удобства экземпляр исключения определяет [`__str__()`](https://python-all.ru/3.9/reference/datamodel.html#object.__str__), так что аргументы можно вывести напрямую без обращения к `.args`. Можно также сначала создать экземпляр исключения, а затем возбудить его и добавить к нему любые атрибуты по желанию.141142```python143>>> try:144... raise Exception('spam', 'eggs')145... except Exception as inst:146... print(type(inst)) # экземпляр исключения147... print(inst.args) # аргументы, хранящиеся в .args148... print(inst) # __str__ позволяет выводить args напрямую, но может быть переопределён в подклассах исключений149... # но может быть переопределён в подклассах исключений150... x, y = inst.args # распаковать args151... print('x =', x)152... print('y =', y)153...154<class 'Exception'>155('spam', 'eggs')156('spam', 'eggs')157x = spam158y = eggs159```160161Если исключение имеет аргументы, они выводятся как последняя часть («подробности») сообщения для необработанных исключений.162163Обработчики исключений обрабатывают исключения не только при их непосредственном возникновении в блоке try, но и если они возникают внутри функций, вызываемых (даже косвенно) в блоке try. Например:164165```python166>>> def this_fails():167... x = 1/0168...169>>> try:170... this_fails()171... except ZeroDivisionError as err:172... print('Handling run-time error:', err)173...174Handling run-time error: division by zero175```176177## 8.4. Возбуждение исключений178179Инструкция [`raise`](https://python-all.ru/3.9/reference/simple_stmts.html#raise) позволяет программисту принудительно вызвать указанное исключение. Например:180181```python182>>> raise NameError('HiThere')183Traceback (most recent call last):184 File "<stdin>", line 1, in <module>185NameError: HiThere186```187188Единственный аргумент [`raise`](https://python-all.ru/3.9/reference/simple_stmts.html#raise) указывает, какое исключение должно быть возбуждено. Это должен быть либо экземпляр исключения, либо класс исключения (класс, который наследуется от [`Exception`](https://python-all.ru/3.9/library/exceptions.html#Exception)). Если передается класс исключения, он будет неявно создан вызовом его конструктора без аргументов:189190```python191raise ValueError # сокращение для 'raise ValueError()'192```193194Если нужно определить, было ли возбуждено исключение, но обрабатывать его не предполагается, более простая форма инструкции [`raise`](https://python-all.ru/3.9/reference/simple_stmts.html#raise) позволяет повторно возбудить исключение:195196```python197>>> try:198... raise NameError('HiThere')199... except NameError:200... print('An exception flew by!')201... raise202...203An exception flew by!204Traceback (most recent call last):205 File "<stdin>", line 2, in <module>206NameError: HiThere207```208209## 8.5. Цепочка исключений210211Оператор [`raise`](https://python-all.ru/3.9/reference/simple_stmts.html#raise) позволяет указать необязательный [`from`](https://python-all.ru/3.9/reference/simple_stmts.html#raise), который включает цепочку исключений. Например:212213```python214# exc должен быть экземпляром исключения или None.215raise RuntimeError from exc216```217218Это может быть полезно при преобразовании исключений. Например:219220```python221>>> def func():222... raise IOError223...224>>> try:225... func()226... except IOError as exc:227... raise RuntimeError('Failed to open database') from exc228...229Traceback (most recent call last):230 File "<stdin>", line 2, in <module>231 File "<stdin>", line 2, in func232OSError233234The above exception was the direct cause of the following exception:235236Traceback (most recent call last):237 File "<stdin>", line 4, in <module>238RuntimeError: Failed to open database239```240241Цепочка исключений создается автоматически, когда исключение возбуждается внутри секции [`except`](https://python-all.ru/3.9/reference/compound_stmts.html#except) или [`finally`](https://python-all.ru/3.9/reference/compound_stmts.html#finally). Цепочку исключений можно отключить, используя идиому `from None`:242243```python244>>> try:245... open('database.sqlite')246... except OSError:247... raise RuntimeError from None248...249Traceback (most recent call last):250 File "<stdin>", line 4, in <module>251RuntimeError252```253254Дополнительную информацию о механизме сцепления см. в разделе [Встроенные исключения](https://python-all.ru/3.9/library/exceptions.html#bltin-exceptions).255256## 8.6. Определяемые пользователем исключения257258Программы могут задавать собственные исключения, создавая новый класс исключения (см. [Классы](https://python-all.ru/3.9/tutorial/classes.html#tut-classes) для получения дополнительной информации о классах Python). Исключения обычно должны быть производными от класса [`Exception`](https://python-all.ru/3.9/library/exceptions.html#Exception), прямо или косвенно.259260Классы исключений могут быть определены так, чтобы делать всё, что может любой другой класс, но обычно их оставляют простыми, часто предоставляя лишь несколько атрибутов, позволяющих обработчикам извлекать информацию об ошибке.261262Большинство исключений имеют имена, оканчивающиеся на «Error», подобно именованию стандартных исключений.263264Многие стандартные модули определяют собственные исключения для сообщения об ошибках, которые могут возникнуть в определяемых ими функциях. Дополнительная информация о классах представлена в главе [Классы](https://python-all.ru/3.9/tutorial/classes.html#tut-classes).265266## 8.7. Определение действий по очистке267268Инструкция [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try) имеет ещё один необязательный блок, предназначенный для определения действий по очистке, которые должны быть выполнены при любых обстоятельствах. Например:269270```python271>>> try:272... raise KeyboardInterrupt273... finally:274... print('Goodbye, world!')275...276Goodbye, world!277Traceback (most recent call last):278 File "<stdin>", line 2, in <module>279KeyboardInterrupt280```281282Если присутствует блок [`finally`](https://python-all.ru/3.9/reference/compound_stmts.html#finally), блок `finally` будет выполнен как последняя задача перед завершением инструкции [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try). Блок `finally` выполняется независимо от того, вызывает ли инструкция `try` исключение. В следующих пунктах рассматриваются более сложные случаи возникновения исключения:283284- Если исключение возникает во время выполнения блока `try`, оно может быть обработано блоком [`except`](https://python-all.ru/3.9/reference/compound_stmts.html#except). Если исключение не обработано блоком `except`, оно повторно возбуждается после выполнения блока `finally`.285- Исключение может возникнуть во время выполнения блока `except` или `else`. В этом случае исключение также повторно возбуждается после выполнения блока `finally`.286- Если в `finally` блоке выполняется оператор [`break`](https://python-all.ru/3.9/reference/simple_stmts.html#break), [`continue`](https://python-all.ru/3.9/reference/simple_stmts.html#continue) или [`return`](https://python-all.ru/3.9/reference/simple_stmts.html#return), исключения не возбуждаются повторно.287- Если инструкция `try` достигает инструкции [`break`](https://python-all.ru/3.9/reference/simple_stmts.html#break), [`continue`](https://python-all.ru/3.9/reference/simple_stmts.html#continue) или [`return`](https://python-all.ru/3.9/reference/simple_stmts.html#return), блок `finally` выполняется непосредственно перед выполнением инструкции `break`, `continue` или `return`.288- Если в `finally` блоке содержится оператор `return`, возвращаемое значение будет взято из оператора `return` блока `finally`, а не из оператора `return` блока `try`.289290Например:291292```python293>>> def bool_return():294... try:295... return True296... finally:297... return False298...299>>> bool_return()300False301```302303Более сложный пример:304305```python306>>> def divide(x, y):307... try:308... result = x / y309... except ZeroDivisionError:310... print("division by zero!")311... else:312... print("result is", result)313... finally:314... print("executing finally clause")315...316>>> divide(2, 1)317result is 2.0318executing finally clause319>>> divide(2, 0)320division by zero!321executing finally clause322>>> divide("2", "1")323executing finally clause324Traceback (most recent call last):325 File "<stdin>", line 1, in <module>326 File "<stdin>", line 3, in divide327TypeError: unsupported operand type(s) for /: 'str' and 'str'328```329330Как видите, блок [`finally`](https://python-all.ru/3.9/reference/compound_stmts.html#finally) выполняется в любом случае. Исключение [`TypeError`](https://python-all.ru/3.9/library/exceptions.html#TypeError), возбуждённое при делении двух строк, не обрабатывается блоком [`except`](https://python-all.ru/3.9/reference/compound_stmts.html#except) и поэтому повторно возбуждается после выполнения блока `finally`.331332В реальных приложениях блок [`finally`](https://python-all.ru/3.9/reference/compound_stmts.html#finally) полезен для освобождения внешних ресурсов (таких как файлы или сетевые соединения) независимо от того, было ли использование ресурса успешным.333334## 8.8. Предопределённые действия по очистке335336Некоторые объекты определяют стандартные действия по очистке, которые должны быть выполнены, когда объект больше не нужен, независимо от успеха или неудачи операции с этим объектом. Рассмотрим следующий пример, в котором предпринимается попытка открыть файл и вывести его содержимое на экран.337338```python339for line in open("myfile.txt"):340 print(line, end="")341```342343Проблема этого кода в том, что файл остаётся открытым в течение неопределённого времени после завершения выполнения этой части кода. В простых скриптах это не проблема, но может стать проблемой для более крупных приложений. Инструкция [`with`](https://python-all.ru/3.9/reference/compound_stmts.html#with) позволяет использовать такие объекты, как файлы, таким образом, чтобы гарантировать их своевременную и корректную очистку.344345```python346with open("myfile.txt") as f:347 for line in f:348 print(line, end="")349```350351После выполнения инструкции файл *f* всегда закрывается, даже если при обработке строк возникла проблема. Объекты, которые, подобно файлам, предоставляют предопределённые действия по очистке, сообщают об этом в своей документации.352