Исключения
Вызов исключений
Если ваш код встречает условие, которое он не знает, как обрабатывать, например, неверный параметр, он должен вызвать соответствующее исключение.
def even_the_odds(odds):
if odds % 2 != 1:
raise ValueError("Did not get an odd number")
return odds + 1
Ловить исключения
Используйте try...except:
перехватывать исключения. Вы должны указать как можно более точное исключение:
try:
x = 5 / 0
except ZeroDivisionError as e:
# `e` is the exception object
print("Got a divide by zero! The exception was:", e)
# handle exceptional case
x = 0
finally:
print "The END"
# it runs no matter what execute.
Класс исключения , который указан - в данном случае, ZeroDivisionError
- перехватывает любое исключение, которое из этого класса или любого подкласса этого исключения.
Например, ZeroDivisionError
подкласс ArithmeticError
:
>>> ZeroDivisionError.__bases__
(<class 'ArithmeticError'>,)
Итак, следующий будет еще поймать ZeroDivisionError
:
try:
5 / 0
except ArithmeticError:
print("Got arithmetic error")
Запуск кода очистки с помощью наконец
Иногда вы можете захотеть, чтобы что-то происходило независимо от того, какое исключение произошло, например, если вам нужно очистить некоторые ресурсы.
, finally
, блок из try
пункта будет происходить независимо от того, были ли какие - либо исключения подняли.
resource = allocate_some_expensive_resource()
try:
do_stuff(resource)
except SomeException as e:
log_error(e)
raise # re-raise the error
finally:
free_expensive_resource(resource)
Эта модель часто лучше обращаться с менеджерами контекста ( с использованием с
утверждением ).
Возрождение исключений
Иногда вы хотите поймать исключение только для его проверки, например, в целях регистрации. После проверки вы хотите, чтобы исключение продолжало распространяться, как и раньше.
В этом случае, просто используйте raise
заявление без каких - либо параметров.
try:
5 / 0
except ZeroDivisionError:
print("Got an error")
raise
Имейте в виду, однако, что кто-то еще выше в стеке вызовов может все же перехватить исключение и как-то обработать его. Готовый вывод может быть неприятным в этом случае, потому что это произойдет в любом случае (пойман или не пойман). Поэтому может быть лучше создать другое исключение, содержащее ваш комментарий о ситуации, а также исходное исключение:
try:
5 / 0
except ZeroDivisionError as e:
raise ZeroDivisionError("Got an error", e)
Но это имеет недостаток , заключающийся в сокращении следа исключения в точности этого raise
в то время как raise
без аргумента сохраняет оригинальный след исключения.
В Python 3 вы можете сохранить первоначальный стек с помощью raise
- from
синтаксисом:
raise ZeroDivisionError("Got an error") from e
Цепные исключения с повышением от
В процессе обработки исключения вы можете вызвать другое исключение. Например, если вы получаете IOError
при чтении из файла, вы можете вызвать ошибку конкретного приложения , чтобы представить пользователям вашей библиотеки, вместо этого.
Вы можете объединить исключения, чтобы показать, как происходит обработка исключений: `` `>>> try: 5/0 за исключением ZeroDivisionError как e: повысить ValueError (" Ошибка деления ") из e Traceback (последний вызов был последним): File" ", строка 2, в ZeroDivisionError: деление на ноль Вышеуказанное исключение было прямой причиной следующего исключения: обратная связь (последний вызов был последним): файл " ", строка 4, в ValueError: Разделение не удалось `` `
Иерархия исключений
Обработка исключений происходит на основе иерархии исключений, определяемой структурой наследования классов исключений.
Например, IOError
и OSError
являются подклассами EnvironmentError
.Код , который ловит IOError
не поймать OSError
.Тем не менее, код , который ловит EnvironmentError
будет ловить как IOError
s и OSError
s.
Иерархия встроенных исключений:
`` `BaseException + - SystemExit + - KeyboardInterrupt + - GeneratorExit + - Exception + - StopIteration + - StandardError | + - BufferError | + - ArithmeticError | | + - FloatingPointError | | + - OverflowError | | + - ZeroDivisionError | + - AssertionError | + - AttributeError | + - EnvironmentError | | + - IOError | | + - OSError | | + - WindowsError (Windows) | | + - VMSError (VMS) | + - EOFError | + - ImportError | + - LookupError | | + - IndexError | | + - KeyError | + - MemoryError | + - NameError | | + - UnboundLocalError | + - ReferenceError | + - RuntimeError | | + - NotImplementedError | + - SyntaxError | | + - IndentationError | | + - TabError | + - SystemError | + - TypeError | + - ValueError | + - UnicodeError | + - UnicodeDecodeError | + - UnicodeEncodeError | + - UnicodeTranslateError + - Предупреждение + - Предупреждение об устаревании + - Предупреждение об ожидании + - Время выполнения + - Синтаксическое предупреждение + - Предупреждение пользователя + - FutureWarning + - ImportWarning + - UnicodeWarning + - BytesWarning `` ` `` `BaseException + - SystemExit + - KeyboardInterrupt + - GeneratorExit + - Exception + - StopIeror + - StopAsyncIteration + - ArithmeticError | + - FloatingPointError | + - OverflowError | + - ZeroDivisionError + - AssertionError + - AttributeError + - BufferError + - EOFError + - ImportError + - LookupError | + - IndexError | + - KeyError + - MemoryError + - NameError | + - UnboundLocalError + - OSError | + - BlockingIOError | + - ChildProcessError | + - ConnectionError | | + - BrokenPipeError | | + - ConnectionAbortedError | | + - ConnectionRefusedError | | + - ConnectionResetError | + - FileExistsError | + - FileNotFoundError | + - InterruptedError | + - IsADirectoryError | + - NotADirectoryError | + - PermissionError | + - ProcessLookupError | + - TimeoutError + - ReferenceError + - RuntimeError | + - NotImplementedError | + - RecursionError + - SyntaxError | + - IndentationError | + - TabError + - SystemError + - TypeError + - ValueError | + - UnicodeError | + - UnicodeDecodeError | + - UnicodeEncodeError | + - UnicodeTranslateError + - Предупреждение + - Предупреждение об устаревании + - Предупреждение об ожидании + - Время выполнения + - Синтаксическое предупреждение + - Предупреждение пользователя + - FutureWarning + - ImportWarning + - UnicodeWarning + - BytesWarning + - ResourceWarning `` `
Исключения тоже объекты
Исключением являются только обычные объекты Python , которые наследуют от встроенного BaseException
.Сценарий Python может использовать raise
заявление , чтобы прервать выполнение, в результате чего Python для печати трассировки стеки из стека вызовов в этой точке и представление экземпляра исключения. Например:
>>> def failing_function():
... raise ValueError('Example error!')
>>> failing_function()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in failing_function
ValueError: Example error!
который говорит , что ValueError
с сообщением 'Example error!'
был поднят нашей failing_function()
, который был выполнен в интерпретаторе.
Код вызова может выбрать обработку любых исключений, которые может вызвать вызов:
>>> try:
... failing_function()
... except ValueError:
... print('Handled the error')
Handled the error
Вы можете разжиться объектов исключения, назначая их в except...
часть кода обработки исключений:
>>> try:
... failing_function()
... except ValueError as e:
... print('Caught exception', repr(e))
Caught exception ValueError('Example error!',)
Полный список встроенных исключений Python вместе с их описаниями можно найти в документации по Python: https://docs.python.org/3.5/library/exceptions.html.А вот полный список организованы иерархически: https://codecamp.ru/documentation/python/1788/exceptions/5535/exception-hierarchy .
Создание пользовательских типов исключений
Создайте класс , унаследованный от Exception
:
class FooException(Exception):
pass
try:
raise FooException("insert description here")
except FooException:
print("A FooException was raised.")
или другой тип исключения:
class NegativeError(ValueError):
pass
def foo(x):
# function that only accepts positive values of x
if x < 0:
raise NegativeError("Cannot process negative numbers")
... # rest of function body
try:
result = foo(int(input("Enter a positive integer: "))) # raw_input in Python 2.x
except NegativeError:
print("You entered a negative number!")
else:
print("The result was " + str(result))
Не лови все!
В то время как это часто заманчивым , чтобы поймать каждый Exception
:
try:
very_difficult_function()
except Exception:
# log / try to reconnect / exit gratiously
finally:
print "The END"
# it runs no matter what execute.
Или даже все (что включает в себя BaseException
и всех его детей , включая Exception
):
try:
even_more_difficult_function()
except:
pass # do whatever needed
В большинстве случаев это плохая практика. Это может поймать больше , чем предполагалось, например, SystemExit
, KeyboardInterrupt
и MemoryError
- каждый из которых обычно следует обращаться иначе , чем обычные системы или логические ошибки. Это также означает, что нет четкого понимания того, что внутренний код может делать неправильно и как правильно восстанавливаться после этого состояния. Если вы ловите каждую ошибку, вы не будете знать, какая ошибка произошла или как ее исправить.
Это чаще называют «маскированием ошибок» и его следует избегать. Пусть ваша программа аварийно завершает работу, а не молча терпит неудачу или, что еще хуже, терпит неудачу на более глубоком уровне исполнения (Представьте, что это транзакционная система)
Обычно эти конструкции используются на самом внешнем уровне программы и регистрируют детали ошибки, чтобы можно было исправить ошибку или обработать ошибку более конкретно.
Поймать несколько исключений
Есть несколько путей , чтобы поймать несколько исключений ,
Первый заключается в создании кортежа типов исключений, которые вы хотите перехватить и обработать таким же образом. Этот пример заставит код игнорировать KeyError
и AttributeError
исключения.
try:
d = {}
a = d[1]
b = d.non_existing_field
except (KeyError, AttributeError) as e:
print("A KeyError or an AttributeError exception has been caught.")
Если вы хотите обрабатывать разные исключения по-разному, вы можете предоставить отдельный блок исключений для каждого типа. В этом примере, мы до сих пор поймать KeyError
и AttributeError
, но обрабатывать исключения по - разному.
try:
d = {}
a = d[1]
b = d.non_existing_field
except KeyError as e:
print("A KeyError has occurred. Exception message:", e)
except AttributeError as e:
print("An AttributeError has occurred. Exception message:", e)
Практические примеры обработки исключений
Пользовательский ввод
Представьте , что вы хотите, чтобы пользователь , чтобы ввести номер через input
.Вы хотите убедиться, что ввод является числом. Вы можете использовать try
/ за except
для этого:
в то время как True: try: nb = int (input('Введите число:')) break, кроме ValueError: print("Это не число, попробуйте еще раз.")
Примечание: Python 2.x будет использовать raw_input
вместо; функция input
существует в Python 2.x , но имеет различную семантику. В приведенном выше примере, input
также будет принимать такие выражения, как 2 + 2
, которая является числом.
Если входные данные не могут быть преобразованы в целое число, ValueError
поднимается. Вы можете поймать его с except
.Если исключение не возникает, break
выскакивает из цикла. После цикла, nb
содержит целое число.
Словари
Представьте , что вы итерация список последовательных целых чисел, как range(n)
, и у вас есть список словарей d
, который содержит информацию о том, что можно сделать , когда вы столкнетесь с некоторыми особыми целыми числами, скажем , пропустить d[i]
последующие.
d = [{7: 3}, {25: 9}, {38: 5}]
for i in range(len(d)):
do_stuff(i)
try:
dic = d[i]
i += dic[i]
except KeyError:
i += 1
KeyError
будет поднят при попытке получить значение из словаря для ключа , который не существует.
еще
Код в блоке еще будет работать , только если никакие исключения не были подняты кодом в try
блоке. Это полезно, если у вас есть какой-то код, который вы не хотите запускать, если выдается исключение, но вы не хотите, чтобы исключения, генерируемые этим кодом, были перехвачены.
Например:
try:
data = {1: 'one', 2: 'two'}
print(data[1])
except KeyError as e:
print('key not found')
else:
raise ValueError()
# Output: one
# Output: ValueError
Обратите внимание , что этот вид else:
не может быть объединен с if
запуске другого придаточного к elif
.Если у вас есть следующее , if
это необходимо , чтобы остаться с отступом ниже, else:
:
try:
...
except ...:
...
else:
if ...:
...
elif ...:
...
else:
...