Try except raise
Сначала выполняется try
(код между ключевыми словами try
и except
).
Если не возникает исключение, except
пропускается и выполнение оператора try
завершается.
Если во время выполнения try
возникает исключение, остальная часть кода пропускается. Затем, если тип исключения соответствует исключению, названному в except
, выполняется код в except
, а затем выполнение продолжается после блока try
/ except
.
Если возникает исключение, которое не соответствует исключению, указанному в except
, оно передается во внешние операторы try
; если обработчик не найден, это состояние является необработанным исключением, и выполнение программы останавливается с сообщениемоб ошибки.
У оператора try
может быть более одного предложения except
. Будет выполнено не более одного обработчика исключений. Обработчики обрабатывают только исключения, которые возникают в соответствующем try
, а не в других обработчиках того же оператора try
. except
может содержать несколько исключений в виде кортежа.
... except (RuntimeError, TypeError, NameError):
... pass
Оператор try
/ except
имеет необязательный else
, который, если присутствует, должен быть определен после всех except
. Это полезно для кода, который должен выполняться, если не возникло исключений и позволяет избежать случайного перехвата исключений, которые не были вызваны в теле try
/ except
Когда возникает исключение, с ним может быть связано значение, также известное как аргумент исключения. Наличие и тип аргумента зависят от типа исключения. В предложении except
может быть указана переменная после имени исключения. Переменная привязана к экземпляру исключения с аргументами, хранящимися в instance.args
. Для удобства в экземпляре исключения определяется __str__()
, поэтому аргументы могут выводиться напрямую, без ссылки на .args
. Можно также сначала создать экземпляр исключения перед его возбуждением и добавить к нему любые атрибуты по желанию.
>>> try:
... raise Exception('spam', 'eggs')
... except Exception as inst:
... print(type(inst)) # the exception instance
... print(inst.args) # arguments stored in .args
... print(inst) # __str__ allows args to be printed directly,
... # but may be overridden in exception subclasses
... x, y = inst.args # unpack args
... print('x =', x)
... print('y =', y)
...
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs
Обработчики исключений обрабатывают исключения не только в том случае, если они возникают сразу в try
, но также и в тех случаях, когда они возникают внутри функций, которые вызываются (даже косвенно) в try
.
Оператор raise
позволяет вызвать указанное исключение. Единственный аргумент оператора указывает на возникшее исключение. Это должен быть либо экземпляр исключения, либо класс исключения (класс, производный от Exception
). Если передан класс исключения, он будет неявно создан путем вызова его конструктора без аргументов.
Поднятое исключение можно распространить
>>> try:
... raise NameError('HiThere')
... except NameError:
... print('An exception flew by!')
... raise
...
An exception flew by!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: HiThere
Оператор from
позволяет выстраивать цепочки исключений
>>> def func():
... raise ConnectionError
...
>>> try:
... func()
... except ConnectionError as exc:
... raise RuntimeError('Failed to open database') from exc
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in func
ConnectionError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError: Failed to open database
Цепь исключений можно отключить используя from None
>>> try:
... open('database.sqlite')
>>> except OSError:
... raise RuntimeError from None
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError
Наконец в try
необязательные действия по очистке, которые должны выполняться при любых обстоятельствах.
>>> try:
... raise KeyboardInterrupt
... finally:
... print('Goodbye, world!')
...
Goodbye, world!
KeyboardInterrupt
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
Если присутствует finally
, оно выполняться как последняя задача перед завершением оператора try
. finally
выполняется независимо от того, вызывает ли оператор try
исключение.
Нюансы:
- Если исключение возникает во время выполнения
try
, исключение может быть обработано вexcept
. Если исключение не обрабатываетсяexcept
, исключение повторно возникает после выполненияfinally
. - Исключение может произойти во время выполнения
except
илиelse
. Опять же, исключение повторно будет поднято после выполненияfinally
. - Если
finally
выполняет оператор break, continue илиreturn
, исключения не возникают повторно. - Если
try
достигает оператораbreak
,continue
илиreturn
, тоfinally
будет выполняться непосредственно перед выполнением оператораbreak
,continue
илиreturn
. - Если
finally
включает операторreturn
, возвращаемое значение будет значением из оператораreturn finally
, а не значением из оператораreturn try
.
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print("division by zero!")
... else:
... print("result is", result)
... finally:
... print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
Основная задача finally
- закрывать коннекшены и дескрипторы файлов, вне зависимости от эксепшенов.
Кроме всего перечисленного, для исключения можно определять пользовательские классы, наследуясь от стандартных.
- [python-standart-library]
- [trace]
- [traceback]
- [2022-09-14-daily-note] custom exception question