10. Обработка ошибок.
Типы ошибок
- Основные идеи обработки ошибок в общем: коды возврата vs обработка исключений.
- В Python для обработки ошибок используются исключения.
- Два основных типа ошибок в Python: синтаксические ошибки и исключения.
- Синтаксические ошибки (SyntaxError) - ошибки синтаксиса языка, возникают во время парсинга файла с исходным кодом.
- Исключения (исключительные ситуации, exceptions) - ошибки возникающие во время выполнения программы.
Исключения
- При возникновении исключения создаётся объект-исключение, который также может содержать дополнительную информацию описывающую ошибку.
- С места возникновения ошибки начинается “раскрутка стека”: программа принудительно возвращается по иерархии вызовов функций до корня.
- Если на этом “пути” исключение никак не обработано, то ошибка приводит к завершению программы.
- Обработка исключений осуществляется с помощью блока try…except.
- Исключения могут возникать явно (оператор raise явно использован в пользовательском коде) и неявно (действия приводящие к ошибке, в т.ч. в сторонних библиотеках).
- В стандартной библиотеке языка определён список встроенных типов исключений.
- Есть возможность создания пользовательских типов исключений.
Рассмотрим простой пример обработки исключения при обращении к несуществующему ключу в словаре:
d = dict() try: print d["a"] except Exception as e: print type(e), e
<type 'exceptions.KeyError'> 'a'
Можно перечислять несколько вариантов перехватываемых (обычно от более точных к менее):
d = dict() try: print d["a"] except KeyError as e: print "I see key error" except Exception as e: print type(e), e
I see key error
Опишем вспомогательные функции:
def f(index): index = int(index) if index != 0: index = index + "a" msg = "Don't do that. Instead of raising bare exceptions, use more specific error type." raise Exception(msg) def catch_that(func, val): try: func(val) except ValueError: print "ValueError. I don't want variable e so I don't mention it" except Exception as e: print "Exception ", type(e) except: print "Something strange is going on here"
catch_that(f, "a") ValueError. I don't want variable e so I don't mention it catch_that(f, -1) Exception <type 'exceptions.TypeError'> catch_that(f, 0) Exception <type 'exceptions.Exception'>
Ещё про перехват
Ещё код
def catch_that_again(f): try: f() except (ValueError, TypeError): print "Hey! I know that guy!" except: print "Huh?" else: print "Everythin is ok" finally: print "Finally!"
def raise_them_all(): raise ValueError()
catch_that_again(raise_them_all) Hey! I know that guy! Finally!
def say_hello(): print "Hello"
catch_that_again(say_hello) Hello Everythin is ok Finally!
def break_things(): raise 1 / 0
catch_that_again(break_things) Huh? Finally!
Замечания по перехвату
- finally позволяет определить действия, которые выполнятся при выходе из блока try..except по любой причине (успешное выполнение, исключение, return, break, continue).
- Внимательнее с “except:” - такую форму использовать не рекомендуется, т.к. она очень просто маскирует ошибки.
- Иногда требуется перехватить исключение, выполнить какие-то действия, и снова отправить исключение это же в путь - в таком случае используйте оператор raise без аргументов.
- Если же в подобном случае указать явно тип исключения в raise при его перевыбрасывании, то потеряется информация (например, stacktrace).