try except finally
Позволяет задать обработчики исключений, а также определить код «уборки» для некоторого набора инструкций.
Данная составная инструкция производит обработку исключений для кода, идущего в блоке try.
Таких блоков может быть несколько и в каждом можно определить свой механизм обработки для того или иного типа исключения (или группы исключений). Все блоки except должны иметь тело, в котором реализуется обработка исключения.
После достижения конца блока исполнение продолжается с места, следующего за всей инструкцией. Из этого следует, что в случае, если существуют обработчики одного и того же исключения вложенные друг в друга, и исключение происходит в теле блока try самого внутреннего, то и обработано оно будет только самым внутренним обработчиком.
Перед исполнением блока except, данные об исключении сохраняются в модуле
Инструкции в этом необязательном блоке выполняются по завершению блока try без исключений, а также без
В этом необязательно блоке можно определить код «уборки». Инструкции из этого блока будут выполнены после выполнения всех прочих блоков, в том числе если исключение не было обработано (в этом случае оно будет возбуждено повторно в конце блока finally автоматически) и если в блоке try присутствуют
Если в блоке имеется инструкция
+py3.0 Если в блоке finally возбуждается новое исключение, то ему в качестве контекста будет назначено прежнее исключение. До -py3.0 в подобных сценариях информация об исключении терялась.
+py3.8 Теперь в блоке finally можно использовать инструкцию continue.
Сама инструкция весьма производительна, если исключения не поднимаются. Дорого обходится непосредственно отлов исключения.
До версии +py2.0 можно было часто видеть конструкцию следующего вида:
Это имело смысл лишь когда ключ присутствовал в словаре в большинстве случаев.
Иначе код выглядел так:
В данном конкретном примере можно было использовать
Использовать описанный ниже подход следует в случаях насущной необходимости, без фанатизма.
При помощи инструкции можно соорудить достаточно функциональное подобие
Этот подход не даст перейти внутрь цикла, но обычно подобное и не требуется, так как считается плохим применением
class MyException1(Exception): pass
class MyChildException1(MyException1): pass
class MyException2(Exception): pass
class MyChildException2(MyException2): pass
class MyException3(Exception): pass
class MyChildException3(MyException3): pass
def make_exception(exception_type):
try:
raise exception_type()
except MyChildException1:
print('MyChildException1')
except (MyChildException2, MyException3):
print('MyChildException2, MyException3')
except:
print('broad except')
make_exception(MyChildException1) # MyChildException1
make_exception(MyException2) # broad except
make_exception(MyChildException3) # MyChildException2, MyException3
Блок try
- Если в ходе исполнения данного блока исключений не будет, то ни один из обработчиков не задействуется.
- Если в ходе исполнения инструкций в этом блоке будет зафиксировано исключение, то начнётся поиск подходящего для него обработчика. Поиск производится по блокам except поочерёдно, поэтому более широкие типы исключений (базовые) имеет смысл ставить после более узких.
Блок except
Таких блоков может быть несколько и в каждом можно определить свой механизм обработки для того или иного типа исключения (или группы исключений). Все блоки except должны иметь тело, в котором реализуется обработка исключения.
После достижения конца блока исполнение продолжается с места, следующего за всей инструкцией. Из этого следует, что в случае, если существуют обработчики одного и того же исключения вложенные друг в друга, и исключение происходит в теле блока try самого внутреннего, то и обработано оно будет только самым внутренним обработчиком.
- Если блок except используется без следующего за ним выражения, то он должен быть последним, потому что в нём производится обработка любых типов.
- Если за блоком следует выражение, то оно будет выполнено. Если полученным в результате выполнения объект «совместим» с исключением, которые мы собираемся обработать, то будут выполнены инструкции, находящиеся в данном блоке. Объект считается совместимым с поднятым исключением, если является классом (непосредственным, либо базовым) исключения, либо кортежем, содержащим элемент, совместимый с исключением.
- Если в ходе поиска обработчик найден не будет, то поиск будет продолжен среди обработчиков окружающего кода по стеку.
На заметку
Исключение распространяется по стеку вызова, если только на его пути не встретится блок finally, возбуждающий другое исключение. В этом случае прежнее исключением будет «потеряно» из-за нового.
- Если в ходе выполнения выражения в блоке except будет случится исключение, то поиск обработчика прерывается. При этом начинается поиск нового обработчика в окружающем коде и по стеку вызова. При этом считается, что вся инструкция try except породила исключение.
- Если найден подходящий блок except, то исключению назначается имя указанное после ключевого слова
as
(до +py.2.5 вместо ключевого слова использоваталсь запятая,
). После чего выполняется код в теле блока.
На заметку
Если вы хотите представить исключение в виде строки, то можете попробовать использовать формат
%r
вместо %s
. Так результирующая строка будет содержать не только текст, переданный в инициализатор, но и название типа исключения.Внимание
Если исключению назначено имя, то оно будет очищено после исполнения блока except. Так сделано потому, что вместе с прикрепленной к нему трассировкой стека, исключение формирует циклическую ссылку со фреймом стека, где хранятся все локальные переменные до следующей сборки мусора.
try:
raise Exception('arg1', 'arg2')
except Exception as e:
print(e)
# >> ('arg1', 'arg2')
Перед исполнением блока except, данные об исключении сохраняются в модуле
sys
и могут быть получены при помощи sys.exc_info()
. На заметку
До +py2.5 нельзя было использовать except совместно с finally, то есть, существовали две формы инструкции:
try ... except
и try ... finally
.Блок else
Инструкции в этом необязательном блоке выполняются по завершению блока try без исключений, а также без
return
, continue
и break
.def make_exception():
try:
return 'try'
except:
return 'except'
else:
return 'else'
make_exception() # 'try'
Блок finally
В этом необязательно блоке можно определить код «уборки». Инструкции из этого блока будут выполнены после выполнения всех прочих блоков, в том числе если исключение не было обработано (в этом случае оно будет возбуждено повторно в конце блока finally автоматически) и если в блоке try присутствуют
return
или break
. При этом информация об исключении недоступна.На заметку
В существующих реализациях употребление
continue
в блоке finally не поддерживается.Если в блоке имеется инструкция
return
или break
информация об исключении (если оно было) будет утеряна:def make_exception():
try:
1/0
finally:
return 'finally'
make_exception() # 'finally'
+py3.0 Если в блоке finally возбуждается новое исключение, то ему в качестве контекста будет назначено прежнее исключение. До -py3.0 в подобных сценариях информация об исключении терялась.
На заметку
Дополнительную информация об исключениях доступна в статье Встроенные исключения
+py3.8 Теперь в блоке finally можно использовать инструкцию continue.
Скорость выполнения
Сама инструкция весьма производительна, если исключения не поднимаются. Дорого обходится непосредственно отлов исключения.
До версии +py2.0 можно было часто видеть конструкцию следующего вида:
try:
value = mydict[key]
except KeyError:
mydict[key] = getvalue(key)
value = mydict[key]
Это имело смысл лишь когда ключ присутствовал в словаре в большинстве случаев.
Иначе код выглядел так:
if key in mydict:
value = mydict[key]
else:
value = mydict[key] = getvalue(key)
В данном конкретном примере можно было использовать
value = dict.setdefault(key, getvalue(key))
, но только если вызов getvalue()
достаточно дёшев (поскольку значение в любом случае будет вычислено).goto
Использовать описанный ниже подход следует в случаях насущной необходимости, без фанатизма.
При помощи инструкции можно соорудить достаточно функциональное подобие
go
и goto
из других языков программирования.class label(Exception): pass # метка для goto
try:
...
if condition: raise label() # переход к метке
...
except label: # реализация по метке
pass
...
Этот подход не даст перейти внутрь цикла, но обычно подобное и не требуется, так как считается плохим применением
goto
.
Синонимы поиска: try except finally, catch, ecxept, goto
В разделе «Compound Statements (составные инструкции, операторы)»:
for in else
if elif else
while else
На заметку
Зарегистрированные пользователи могут добавлять Книги.