errors.md
1> **Источник:** https://python-all.ru/3.8/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.8/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't convert 'int' object to str implicitly42```4344Последняя строка сообщения об ошибке показывает, что произошло. Исключения бывают разных типов, и тип выводится как часть сообщения: в примере это [`ZeroDivisionError`](https://python-all.ru/3.8/library/exceptions.html#ZeroDivisionError), [`NameError`](https://python-all.ru/3.8/library/exceptions.html#NameError) и [`TypeError`](https://python-all.ru/3.8/library/exceptions.html#TypeError). Строка, выводимая как тип исключения, – это имя встроенного исключения, которое произошло. Это верно для всех встроенных исключений, но не обязательно для определяемых пользователем (хотя это полезное соглашение). Стандартные имена исключений – встроенные идентификаторы (не зарезервированные ключевые слова).4546Остальная часть строки содержит подробности в зависимости от типа исключения и того, что его вызвало.4748Предыдущая часть сообщения об ошибке показывает контекст, в котором произошло исключение, в виде трассировки стека. Обычно она содержит трассировку стека с перечислением строк исходного кода; однако строки, прочитанные из стандартного ввода, отображаться не будут.4950[Встроенные исключения](https://python-all.ru/3.8/library/exceptions.html#bltin-exceptions) содержит список встроенных исключений и их значение.5152## 8.3. Обработка исключений5354Можно писать программы, обрабатывающие выбранные исключения. В следующем примере показан запрос ввода у пользователя до тех пор, пока не будет введено целое число, но при этом пользователь может прервать программу (с помощью `Control-C` или того, что поддерживает операционная система); обратите внимание, что прерывание пользователем вызывает исключение [`KeyboardInterrupt`](https://python-all.ru/3.8/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.8/reference/compound_stmts.html#try) работает следующим образом.6768- Сначала выполняется *try-блок* (инструкции между ключевыми словами [`try`](https://python-all.ru/3.8/reference/compound_stmts.html#try) и [`except`](https://python-all.ru/3.8/reference/compound_stmts.html#except)).69- Если исключение не произошло, *except-блок* пропускается, и выполнение инструкции [`try`](https://python-all.ru/3.8/reference/compound_stmts.html#try) завершается.70- Если при выполнении блока try возникает исключение, оставшаяся часть блока пропускается. Затем, если его тип совпадает с исключением, указанным после [`except`](https://python-all.ru/3.8/reference/compound_stmts.html#except) ключевого слова, выполняется блок except, и затем выполнение продолжается после оператора [`try`](https://python-all.ru/3.8/reference/compound_stmts.html#try).71- Если возникает исключение, которое не соответствует исключению, указанному в блоке except, оно передается внешним операторам [`try`](https://python-all.ru/3.8/reference/compound_stmts.html#try); если обработчик не найден, это *необработанное исключение* и выполнение останавливается с сообщением, как показано выше.7273Оператор [`try`](https://python-all.ru/3.8/reference/compound_stmts.html#try) может содержать более одного блока except для указания обработчиков разных исключений. Будет выполнен не более одного обработчика. Обработчики обрабатывают только исключения, возникшие в соответствующем блоке try, а не в других обработчиках того же оператора `try`. Блок except может указывать несколько исключений в виде кортежа в скобках, например:7475```python76... except (RuntimeError, TypeError, NameError):77... pass78```7980Класс в блоке [`except`](https://python-all.ru/3.8/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.8/reference/compound_stmts.html#try) … [`except`](https://python-all.ru/3.8/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.8/reference/compound_stmts.html#try), поскольку это позволяет избежать случайного перехвата исключения, которое не было возбуждено кодом, защищённым инструкцией `try` … `except`.137138Когда возникает исключение, оно может иметь связанное значение, также известное как *аргумент* исключения. Наличие и тип аргумента зависят от типа исключения.139140Блок except может указывать переменную после имени исключения. Эта переменная связывается с экземпляром исключения, аргументы которого хранятся в `instance.args`. Для удобства экземпляр исключения определяет [`__str__()`](https://python-all.ru/3.8/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.8/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.8/reference/simple_stmts.html#raise) указывает, какое исключение должно быть возбуждено. Это должен быть либо экземпляр исключения, либо класс исключения (класс, который наследуется от [`Exception`](https://python-all.ru/3.8/library/exceptions.html#Exception)). Если передается класс исключения, он будет неявно создан вызовом его конструктора без аргументов:189190```python191raise ValueError # сокращение для 'raise ValueError()'192```193194Если нужно определить, было ли возбуждено исключение, но обрабатывать его не предполагается, более простая форма инструкции [`raise`](https://python-all.ru/3.8/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Программы могут задавать собственные исключения, создавая новый класс исключения (см. [Классы](https://python-all.ru/3.8/tutorial/classes.html#tut-classes) для получения дополнительной информации о классах Python). Исключения обычно должны быть производными от класса [`Exception`](https://python-all.ru/3.8/library/exceptions.html#Exception), прямо или косвенно.212213Классы исключений можно определять так же, как любые другие классы, но обычно их делают простыми, часто предоставляя лишь несколько атрибутов, позволяющих обработчикам исключений извлекать информацию об ошибке. При создании модуля, который может вызывать несколько различных ошибок, распространённой практикой является создание базового класса для исключений, определённых в этом модуле, и наследование от него для создания конкретных классов исключений для разных условий ошибок:214215```python216class Error(Exception):217 """Базовый класс для исключений в этом модуле."""218 pass219220class InputError(Error):221 """Исключение, возникающее при ошибках ввода.222223 Атрибуты:224 expression -- входное выражение, в котором произошла ошибка225 message -- пояснение ошибки226 """227228 def __init__(self, expression, message):229 self.expression = expression230 self.message = message231232class TransitionError(Error):233 """Возникает, когда операция пытается выполнить переход состояния, который не234 разрешён.235236 Атрибуты:237 previous -- состояние в начале перехода238 next -- новое состояние, которое было запрошено239 message -- пояснение, почему конкретный переход не разрешён240 """241242 def __init__(self, previous, next, message):243 self.previous = previous244 self.next = next245 self.message = message246```247248Большинство исключений имеют имена, оканчивающиеся на «Error», подобно именованию стандартных исключений.249250Многие стандартные модули определяют собственные исключения для сообщения об ошибках, которые могут возникнуть в определяемых ими функциях. Дополнительная информация о классах представлена в главе [Классы](https://python-all.ru/3.8/tutorial/classes.html#tut-classes).251252## 8.6. Определение действий по очистке253254Инструкция [`try`](https://python-all.ru/3.8/reference/compound_stmts.html#try) имеет ещё один необязательный блок, предназначенный для определения действий по очистке, которые должны быть выполнены при любых обстоятельствах. Например:255256```python257>>> try:258... raise KeyboardInterrupt259... finally:260... print('Goodbye, world!')261...262Goodbye, world!263Traceback (most recent call last):264 File "<stdin>", line 2, in <module>265KeyboardInterrupt266```267268Если присутствует блок [`finally`](https://python-all.ru/3.8/reference/compound_stmts.html#finally), блок `finally` будет выполнен как последняя задача перед завершением инструкции [`try`](https://python-all.ru/3.8/reference/compound_stmts.html#try). Блок `finally` выполняется независимо от того, вызывает ли инструкция `try` исключение. В следующих пунктах рассматриваются более сложные случаи возникновения исключения:269270- Если исключение возникает во время выполнения блока `try`, оно может быть обработано блоком [`except`](https://python-all.ru/3.8/reference/compound_stmts.html#except). Если исключение не обработано блоком `except`, оно повторно возбуждается после выполнения блока `finally`.271- Исключение может возникнуть во время выполнения блока `except` или `else`. В этом случае исключение также повторно возбуждается после выполнения блока `finally`.272- Если инструкция `try` достигает инструкции [`break`](https://python-all.ru/3.8/reference/simple_stmts.html#break), [`continue`](https://python-all.ru/3.8/reference/simple_stmts.html#continue) или [`return`](https://python-all.ru/3.8/reference/simple_stmts.html#return), блок `finally` выполняется непосредственно перед выполнением инструкции `break`, `continue` или `return`.273- Если в `finally` блоке содержится оператор `return`, возвращаемое значение будет взято из оператора `return` блока `finally`, а не из оператора `return` блока `try`.274275Например:276277```python278>>> def bool_return():279... try:280... return True281... finally:282... return False283...284>>> bool_return()285False286```287288Более сложный пример:289290```python291>>> def divide(x, y):292... try:293... result = x / y294... except ZeroDivisionError:295... print("division by zero!")296... else:297... print("result is", result)298... finally:299... print("executing finally clause")300...301>>> divide(2, 1)302result is 2.0303executing finally clause304>>> divide(2, 0)305division by zero!306executing finally clause307>>> divide("2", "1")308executing finally clause309Traceback (most recent call last):310 File "<stdin>", line 1, in <module>311 File "<stdin>", line 3, in divide312TypeError: unsupported operand type(s) for /: 'str' and 'str'313```314315Как видите, блок [`finally`](https://python-all.ru/3.8/reference/compound_stmts.html#finally) выполняется в любом случае. Исключение [`TypeError`](https://python-all.ru/3.8/library/exceptions.html#TypeError), возбуждённое при делении двух строк, не обрабатывается блоком [`except`](https://python-all.ru/3.8/reference/compound_stmts.html#except) и поэтому повторно возбуждается после выполнения блока `finally`.316317В реальных приложениях блок [`finally`](https://python-all.ru/3.8/reference/compound_stmts.html#finally) полезен для освобождения внешних ресурсов (таких как файлы или сетевые соединения) независимо от того, было ли использование ресурса успешным.318319## 8.7. Предопределённые действия по очистке320321Некоторые объекты определяют стандартные действия по очистке, которые должны быть выполнены, когда объект больше не нужен, независимо от успеха или неудачи операции с этим объектом. Рассмотрим следующий пример, в котором предпринимается попытка открыть файл и вывести его содержимое на экран.322323```python324for line in open("myfile.txt"):325 print(line, end="")326```327328Проблема этого кода в том, что файл остаётся открытым в течение неопределённого времени после завершения выполнения этой части кода. В простых скриптах это не проблема, но может стать проблемой для более крупных приложений. Инструкция [`with`](https://python-all.ru/3.8/reference/compound_stmts.html#with) позволяет использовать такие объекты, как файлы, таким образом, чтобы гарантировать их своевременную и корректную очистку.329330```python331with open("myfile.txt") as f:332 for line in f:333 print(line, end="")334```335336После выполнения инструкции файл *f* всегда закрывается, даже если при обработке строк возникла проблема. Объекты, которые, подобно файлам, предоставляют предопределённые действия по очистке, сообщают об этом в своей документации.337