errors.md
1> **Источник:** https://python-all.ru/3.10/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.10/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.10/library/exceptions.html#ZeroDivisionError), [`NameError`](https://python-all.ru/3.10/library/exceptions.html#NameError) и [`TypeError`](https://python-all.ru/3.10/library/exceptions.html#TypeError). Строка, выводимая как тип исключения, – это имя встроенного исключения, которое произошло. Это верно для всех встроенных исключений, но не обязательно для определяемых пользователем (хотя это полезное соглашение). Стандартные имена исключений – встроенные идентификаторы (не зарезервированные ключевые слова).4546Остальная часть строки содержит подробности в зависимости от типа исключения и того, что его вызвало.4748Предшествующая часть сообщения об ошибке показывает контекст, в котором произошло исключение, в виде трассировки стека. Обычно она содержит трассировку стека с перечислением строк исходного кода; однако строки, прочитанные из стандартного ввода, не отображаются.4950[Встроенные исключения](https://python-all.ru/3.10/library/exceptions.html#bltin-exceptions) содержит список встроенных исключений и их значение.5152## 8.3. Обработка исключений5354Можно писать программы, обрабатывающие выбранные исключения. В следующем примере показан запрос ввода у пользователя до тех пор, пока не будет введено целое число, но при этом пользователь может прервать программу (с помощью `Control-C` или того, что поддерживает операционная система); обратите внимание, что прерывание пользователем вызывает исключение [`KeyboardInterrupt`](https://python-all.ru/3.10/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.10/reference/compound_stmts.html#try) работает следующим образом.6768- Сначала выполняется *try-блок* (инструкции между ключевыми словами [`try`](https://python-all.ru/3.10/reference/compound_stmts.html#try) и [`except`](https://python-all.ru/3.10/reference/compound_stmts.html#except)).69- Если исключение не произошло, *except-блок* пропускается, и выполнение инструкции [`try`](https://python-all.ru/3.10/reference/compound_stmts.html#try) завершается.70- Если во время выполнения [`try`](https://python-all.ru/3.10/reference/compound_stmts.html#try)-блока происходит исключение, оставшаяся часть этого блока пропускается. Затем, если его тип совпадает с исключением, указанным после ключевого слова [`except`](https://python-all.ru/3.10/reference/compound_stmts.html#except), выполняется *except-блок*, после чего выполнение продолжается за пределами блока try/except.71- Если возникает исключение, которое не соответствует исключению, указанному в *предложении except*, оно передается внешним [`try`](https://python-all.ru/3.10/reference/compound_stmts.html#try) операторам; если обработчик не найден, это *необработанное исключение*, и выполнение останавливается с сообщением, как показано выше.7273Оператор [`try`](https://python-all.ru/3.10/reference/compound_stmts.html#try) может иметь более одного *блока except* для указания обработчиков разных исключений. Будет выполнен не более одного обработчика. Обработчики обрабатывают только исключения, возникшие в соответствующем *блоке try*, а не в других обработчиках того же оператора `try`. *Блок except* может указывать несколько исключений в виде кортежа в скобках, например:7475```python76... except (RuntimeError, TypeError, NameError):77... pass78```7980Класс в предложении [`except`](https://python-all.ru/3.10/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Все исключения наследуются от [`BaseException`](https://python-all.ru/3.10/library/exceptions.html#BaseException), поэтому его можно использовать в качестве универсального обработчика. Используйте это с крайней осторожностью, поскольку таким образом легко скрыть настоящую ошибку программирования! Его также можно использовать для вывода сообщения об ошибке и последующего повторного возбуждения исключения (позволяя вызывающему коду также обработать исключение):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 BaseException as err:119 print(f"Unexpected {err=}, {type(err)=}")120 raise121```122123В качестве альтернативы последнее предложение except может опускать имя (имена) исключения, однако тогда значение исключения должно быть получено из `sys.exc_info()[1]`.124125Инструкция [`try`](https://python-all.ru/3.10/reference/compound_stmts.html#try) … [`except`](https://python-all.ru/3.10/reference/compound_stmts.html#except) имеет необязательный *блок else*, который, если присутствует, должен следовать за всеми *блоками except*. Он полезен для кода, который должен быть выполнен, если *блок try* не возбуждает исключение. Например:126127```python128for arg in sys.argv[1:]:129 try:130 f = open(arg, 'r')131 except OSError:132 print('cannot open', arg)133 else:134 print(arg, 'has', len(f.readlines()), 'lines')135 f.close()136```137138Использование блока `else` лучше, чем добавление дополнительного кода в блок [`try`](https://python-all.ru/3.10/reference/compound_stmts.html#try), поскольку это позволяет избежать случайного перехвата исключения, которое не было возбуждено кодом, защищённым инструкцией `try` … `except`.139140Когда возникает исключение, оно может иметь связанное значение, также известное как *аргумент* исключения. Наличие и тип аргумента зависят от типа исключения.141142*Предложение except* может указывать переменную после имени исключения. Эта переменная привязывается к экземпляру исключения с аргументами, хранящимися в `instance.args`. Для удобства экземпляр исключения определяет `__str__()`, чтобы аргументы можно было вывести напрямую без необходимости обращаться к `.args`. Можно также сначала создать экземпляр исключения перед его возбуждением и добавить к нему любые атрибуты по желанию.143144```python145>>> try:146... raise Exception('spam', 'eggs')147... except Exception as inst:148... print(type(inst)) # экземпляр исключения149... print(inst.args) # аргументы, хранящиеся в .args150... print(inst) # __str__ позволяет выводить args напрямую, но может быть переопределён в подклассах исключений151... # но может быть переопределён в подклассах исключений152... x, y = inst.args # распаковать args153... print('x =', x)154... print('y =', y)155...156<class 'Exception'>157('spam', 'eggs')158('spam', 'eggs')159x = spam160y = eggs161```162163Если исключение имеет аргументы, они выводятся как последняя часть («подробности») сообщения для необработанных исключений.164165Обработчики исключений обрабатывают исключения не только в том случае, если они возникают непосредственно в *блоке try*, но и если они возникают внутри функций, вызываемых (даже косвенно) в *блоке try*. Например:166167```python168>>> def this_fails():169... x = 1/0170...171>>> try:172... this_fails()173... except ZeroDivisionError as err:174... print('Handling run-time error:', err)175...176Handling run-time error: division by zero177```178179## 8.4. Возбуждение исключений180181Инструкция [`raise`](https://python-all.ru/3.10/reference/simple_stmts.html#raise) позволяет программисту принудительно вызвать указанное исключение. Например:182183```python184>>> raise NameError('HiThere')185Traceback (most recent call last):186 File "<stdin>", line 1, in <module>187NameError: HiThere188```189190Единственный аргумент [`raise`](https://python-all.ru/3.10/reference/simple_stmts.html#raise) указывает, какое исключение должно быть возбуждено. Это должен быть либо экземпляр исключения, либо класс исключения (класс, который наследуется от [`Exception`](https://python-all.ru/3.10/library/exceptions.html#Exception)). Если передается класс исключения, он будет неявно создан вызовом его конструктора без аргументов:191192```python193raise ValueError # сокращение для 'raise ValueError()'194```195196Если нужно определить, было ли возбуждено исключение, но обрабатывать его не предполагается, более простая форма инструкции [`raise`](https://python-all.ru/3.10/reference/simple_stmts.html#raise) позволяет повторно возбудить исключение:197198```python199>>> try:200... raise NameError('HiThere')201... except NameError:202... print('An exception flew by!')203... raise204...205An exception flew by!206Traceback (most recent call last):207 File "<stdin>", line 2, in <module>208NameError: HiThere209```210211## 8.5. Цепочка исключений212213Если необработанное исключение возникает внутри раздела [`except`](https://python-all.ru/3.10/reference/compound_stmts.html#except), к нему будет присоединено обрабатываемое исключение, и оно будет включено в сообщение об ошибке:214215```python216>>> try:217... open("database.sqlite")218... except OSError:219... raise RuntimeError("unable to handle error")220...221Traceback (most recent call last):222 File "<stdin>", line 2, in <module>223FileNotFoundError: [Errno 2] No such file or directory: 'database.sqlite'224225During handling of the above exception, another exception occurred:226227Traceback (most recent call last):228 File "<stdin>", line 4, in <module>229RuntimeError: unable to handle error230```231232Чтобы указать, что исключение является прямым следствием другого, инструкция [`raise`](https://python-all.ru/3.10/reference/simple_stmts.html#raise) допускает необязательный блок [`from`](https://python-all.ru/3.10/reference/simple_stmts.html#raise):233234```python235# exc должен быть экземпляром исключения или None.236raise RuntimeError from exc237```238239Это может быть полезно при преобразовании исключений. Например:240241```python242>>> def func():243... raise ConnectionError244...245>>> try:246... func()247... except ConnectionError as exc:248... raise RuntimeError('Failed to open database') from exc249...250Traceback (most recent call last):251 File "<stdin>", line 2, in <module>252 File "<stdin>", line 2, in func253ConnectionError254255The above exception was the direct cause of the following exception:256257Traceback (most recent call last):258 File "<stdin>", line 4, in <module>259RuntimeError: Failed to open database260```261262Он также позволяет отключить автоматическое сцепление исключений с помощью идиомы `from None`:263264```python265>>> try:266... open('database.sqlite')267... except OSError:268... raise RuntimeError from None269...270Traceback (most recent call last):271 File "<stdin>", line 4, in <module>272RuntimeError273```274275Дополнительную информацию о механизме сцепления см. в разделе [Встроенные исключения](https://python-all.ru/3.10/library/exceptions.html#bltin-exceptions).276277## 8.6. Определяемые пользователем исключения278279Программы могут задавать собственные исключения, создавая новый класс исключения (см. [Классы](https://python-all.ru/3.10/tutorial/classes.html#tut-classes) для получения дополнительной информации о классах Python). Исключения обычно должны быть производными от класса [`Exception`](https://python-all.ru/3.10/library/exceptions.html#Exception), прямо или косвенно.280281Классы исключений могут быть определены так, чтобы делать всё, что может любой другой класс, но обычно их оставляют простыми, часто предоставляя лишь несколько атрибутов, позволяющих обработчикам извлекать информацию об ошибке.282283Большинство исключений имеют имена, оканчивающиеся на «Error», подобно именованию стандартных исключений.284285Многие стандартные модули определяют собственные исключения для сообщения об ошибках, которые могут возникнуть в определяемых ими функциях. Дополнительная информация о классах представлена в главе [Классы](https://python-all.ru/3.10/tutorial/classes.html#tut-classes).286287## 8.7. Определение действий по очистке288289Инструкция [`try`](https://python-all.ru/3.10/reference/compound_stmts.html#try) имеет ещё один необязательный блок, предназначенный для определения действий по очистке, которые должны быть выполнены при любых обстоятельствах. Например:290291```python292>>> try:293... raise KeyboardInterrupt294... finally:295... print('Goodbye, world!')296...297Goodbye, world!298Traceback (most recent call last):299 File "<stdin>", line 2, in <module>300KeyboardInterrupt301```302303Если присутствует блок [`finally`](https://python-all.ru/3.10/reference/compound_stmts.html#finally), блок `finally` будет выполнен как последняя задача перед завершением инструкции [`try`](https://python-all.ru/3.10/reference/compound_stmts.html#try). Блок `finally` выполняется независимо от того, вызывает ли инструкция `try` исключение. В следующих пунктах рассматриваются более сложные случаи возникновения исключения:304305- Если исключение возникает во время выполнения блока `try`, оно может быть обработано блоком [`except`](https://python-all.ru/3.10/reference/compound_stmts.html#except). Если исключение не обработано блоком `except`, оно повторно возбуждается после выполнения блока `finally`.306- Исключение может возникнуть во время выполнения блока `except` или `else`. В этом случае исключение также повторно возбуждается после выполнения блока `finally`.307- Если в `finally` блоке выполняется оператор [`break`](https://python-all.ru/3.10/reference/simple_stmts.html#break), [`continue`](https://python-all.ru/3.10/reference/simple_stmts.html#continue) или [`return`](https://python-all.ru/3.10/reference/simple_stmts.html#return), исключения не возбуждаются повторно.308- Если инструкция `try` достигает инструкции [`break`](https://python-all.ru/3.10/reference/simple_stmts.html#break), [`continue`](https://python-all.ru/3.10/reference/simple_stmts.html#continue) или [`return`](https://python-all.ru/3.10/reference/simple_stmts.html#return), блок `finally` выполняется непосредственно перед выполнением инструкции `break`, `continue` или `return`.309- Если в `finally` блоке содержится оператор `return`, возвращаемое значение будет взято из оператора `return` блока `finally`, а не из оператора `return` блока `try`.310311Например:312313```python314>>> def bool_return():315... try:316... return True317... finally:318... return False319...320>>> bool_return()321False322```323324Более сложный пример:325326```python327>>> def divide(x, y):328... try:329... result = x / y330... except ZeroDivisionError:331... print("division by zero!")332... else:333... print("result is", result)334... finally:335... print("executing finally clause")336...337>>> divide(2, 1)338result is 2.0339executing finally clause340>>> divide(2, 0)341division by zero!342executing finally clause343>>> divide("2", "1")344executing finally clause345Traceback (most recent call last):346 File "<stdin>", line 1, in <module>347 File "<stdin>", line 3, in divide348TypeError: unsupported operand type(s) for /: 'str' and 'str'349```350351Как видите, блок [`finally`](https://python-all.ru/3.10/reference/compound_stmts.html#finally) выполняется в любом случае. Исключение [`TypeError`](https://python-all.ru/3.10/library/exceptions.html#TypeError), возбуждённое при делении двух строк, не обрабатывается блоком [`except`](https://python-all.ru/3.10/reference/compound_stmts.html#except) и поэтому повторно возбуждается после выполнения блока `finally`.352353В реальных приложениях блок [`finally`](https://python-all.ru/3.10/reference/compound_stmts.html#finally) полезен для освобождения внешних ресурсов (таких как файлы или сетевые соединения) независимо от того, было ли использование ресурса успешным.354355## 8.8. Предопределённые действия по очистке356357Некоторые объекты определяют стандартные действия по очистке, которые должны быть выполнены, когда объект больше не нужен, независимо от успеха или неудачи операции с этим объектом. Рассмотрим следующий пример, в котором предпринимается попытка открыть файл и вывести его содержимое на экран.358359```python360for line in open("myfile.txt"):361 print(line, end="")362```363364Проблема этого кода в том, что файл остаётся открытым в течение неопределённого времени после завершения выполнения этой части кода. В простых скриптах это не проблема, но может стать проблемой для более крупных приложений. Инструкция [`with`](https://python-all.ru/3.10/reference/compound_stmts.html#with) позволяет использовать такие объекты, как файлы, таким образом, чтобы гарантировать их своевременную и корректную очистку.365366```python367with open("myfile.txt") as f:368 for line in f:369 print(line, end="")370```371372После выполнения инструкции файл *f* всегда закрывается, даже если при обработке строк возникла проблема. Объекты, которые, подобно файлам, предоставляют предопределённые действия по очистке, сообщают об этом в своей документации.373