Документация Python неофициальный перевод
Содержание страницы

Обработка исключенийException Handling

Функции, описанные в этой главе, позволяют обрабатывать и возбуждать исключения Python. Важно понимать некоторые основы обработки исключений в Python. Механизм в чём-то похож на переменную errno в Unix: существует глобальный индикатор (на поток) последней произошедшей ошибки. Большинство функций не сбрасывают его при успехе, но устанавливают, чтобы указать причину ошибки в случае неудачи. Большинство функций также возвращают индикатор ошибки – обычно NULL, если ожидается возврат указателя, или -1, если возвращается целое число (исключение: функции PyArg_*() возвращают 1 при успехе и 0 при ошибке).

Когда функция должна завершиться ошибкой, потому что вызванная ей функция завершилась ошибкой, она обычно не устанавливает индикатор ошибки; его уже установила вызванная функция. Она отвечает либо за обработку ошибки и очистку исключения, либо за возврат после освобождения всех удерживаемых ресурсов (таких как ссылки на объекты или выделенная память); она не должна продолжать нормальное выполнение, если не готова обработать ошибку. При возврате из-за ошибки важно указать вызывающему коду, что ошибка была установлена. Если ошибка не обрабатывается или не аккуратно распространяется, последующие вызовы Python/C API могут вести себя не так, как задумано, и могут отказать загадочным образом.

Индикатор ошибки состоит из трёх объектов Python, соответствующих результату вызова sys.exc_info(). Существуют функции API для взаимодействия с индикатором ошибки разными способами. Для каждого потока предусмотрен отдельный индикатор ошибки.

void PyErr_PrintEx(int set_sys_last_vars)

Выводит стандартную трассировку в sys.stderr и очищает индикатор ошибки. Вызывайте эту функцию только при установленном индикаторе ошибки (иначе возникнет фатальная ошибка!).

Если set_sys_last_vars не равно нулю, переменные sys.last_type, sys.last_value и sys.last_traceback будут установлены в тип, значение и трассировку напечатанного исключения соответственно.

void PyErr_Print()
Псевдоним для PyErr_PrintEx(1).
PyObject* PyErr_Occurred()
Возвращаемое значение: заимствованная ссылка.

Проверяет, установлен ли индикатор ошибки. Если установлен, возвращает тип исключения (первый аргумент последнего вызова одной из функций PyErr_Set*() или PyErr_Restore()). Если не установлен, возвращает NULL. Вы не владеете ссылкой на возвращаемое значение, поэтому не нужно вызывать Py_DECREF().

Примечание

Не сравнивайте возвращаемое значение с конкретным исключением; используйте PyErr_ExceptionMatches(), как показано ниже. (Сравнение может легко завершиться неудачей, так как исключение может быть экземпляром, а не классом, в случае исключения-класса, или оно может быть подклассом ожидаемого исключения.)

int PyErr_ExceptionMatches(PyObject *exc)
Эквивалентно PyErr_GivenExceptionMatches(PyErr_Occurred(), exc). Функцию следует вызывать только тогда, когда исключение действительно установлено; в противном случае возникнет нарушение доступа к памяти.
int PyErr_GivenExceptionMatches(PyObject *given, PyObject *exc)
Возвращает истину, если исключение given соответствует исключению в exc. Если exc – объект класса, также возвращает истину, когда given является экземпляром подкласса. Если exc – кортеж, выполняется поиск совпадения по всем исключениям кортежа (и рекурсивно по вложенным кортежам).
void PyErr_NormalizeException(PyObject**exc, PyObject**val, PyObject**tb)
При определённых обстоятельствах значения, возвращаемые PyErr_Fetch() (см. ниже), могут оказаться «ненормализованными»: *exc является объектом класса, но *val не является экземпляром того же класса. Данная функция позволяет инстанцировать класс в таком случае. Если значения уже нормализованы, ничего не происходит. Отложенная нормализация реализована для повышения производительности.
void PyErr_Clear()
Очищает индикатор ошибки. Если индикатор ошибки не установлен, эффекта нет.
void PyErr_Fetch(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback)

Извлекает индикатор ошибки в три переменные, адреса которых передаются. Если индикатор ошибки не установлен, устанавливает все три переменные в NULL. Если установлен, он будет очищен, и вы получаете владение ссылкой на каждый извлечённый объект. Значение и объект traceback могут быть NULL, даже если объект типа не NULL.

Примечание

Эта функция обычно используется только кодом, которому нужно обрабатывать исключения, или кодом, которому требуется временно сохранить и восстановить индикатор ошибки.

void PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)

Set the error indicator from the three objects. If the error indicator is already set, it is cleared first. If the objects are NULL, the error indicator is cleared. Do not pass a NULL type and non-NULL value or traceback. The exception type should be a class. Do not pass an invalid exception type or value. (Violating these rules will cause subtle problems later.) This call takes away a reference to each object: you must own a reference to each object before the call and after the call you no longer own these references. (If you don’t understand this, don’t use this function. I warned you.)

Примечание

Эта функция обычно используется только кодом, которому нужно временно сохранить и восстановить индикатор ошибки; для сохранения текущего состояния исключения используйте PyErr_Fetch().

void PyErr_SetString(PyObject *type, const char *message)
Это наиболее распространённый способ установки индикатора ошибки. Первый аргумент задаёт тип исключения; обычно это одно из стандартных исключений, например PyExc_RuntimeError. Увеличивать его счётчик ссылок не требуется. Второй аргумент – сообщение об ошибке; оно преобразуется в строковый объект.
void PyErr_SetObject(PyObject *type, PyObject *value)
Эта функция аналогична PyErr_SetString(), но позволяет указать произвольный объект Python для параметра «value» исключения.
PyObject* PyErr_Format(PyObject *exception, const char *format, ...)
Возвращаемое значение: всегда NULL.

Эта функция устанавливает индикатор ошибки и возвращает NULL. исключение должно быть классом исключения Python. Параметры format и последующие помогают отформатировать сообщение об ошибке; они имеют тот же смысл и значения, что и в PyUnicode_FromFormat().

void PyErr_SetNone(PyObject *type)
Это сокращённая запись для PyErr_SetObject(type, Py_None).
int PyErr_BadArgument()
Это сокращённая запись для PyErr_SetString(PyExc_TypeError, message), где message указывает, что встроенная операция была вызвана с недопустимым аргументом. В основном используется внутри.
PyObject* PyErr_NoMemory()
Возвращаемое значение: всегда NULL.

Это сокращённая запись для PyErr_SetNone(PyExc_MemoryError); она возвращает NULL, чтобы функция выделения объекта могла написать return PyErr_NoMemory(); при нехватке памяти.

PyObject* PyErr_SetFromErrno(PyObject *type)
Возвращаемое значение: всегда NULL.

Это вспомогательная функция для возбуждения исключения, когда функция библиотеки C вернула ошибку и установила переменную C errno. Она создаёт объект-кортеж, первый элемент которого – целое значение errno, а второй – соответствующее сообщение об ошибке (полученное через strerror()), и затем вызывает PyErr_SetObject(type, object). В Unix, когда значение errno равно EINTR, что указывает на прерванный системный вызов, эта функция вызывает PyErr_CheckSignals(), и если тот установил индикатор ошибки, оставляет его таким. Функция всегда возвращает NULL, поэтому обёрточная функция вокруг системного вызова может написать return PyErr_SetFromErrno(type); когда системный вызов возвращает ошибку.

PyObject* PyErr_SetFromErrnoWithFilename(PyObject *type, const char *filename)
Возвращаемое значение: всегда NULL.

Похожа на PyErr_SetFromErrno(), с дополнительным поведением: если filename не равен NULL, он передаётся конструктору type в качестве третьего параметра. Для таких исключений, как IOError и OSError, это используется для определения атрибута filename экземпляра исключения.

PyObject* PyErr_SetFromWindowsErr(int ierr)
Возвращаемое значение: всегда NULL.

Это вспомогательная функция для возбуждения WindowsError. Если вызвана с ierr равным 0, используется код ошибки, возвращённый вызовом GetLastError(). Она вызывает функцию Win32 FormatMessage(), чтобы получить описание Windows для кода ошибки, заданного ierr или GetLastError(), затем создаёт объект-кортеж, первый элемент которого – значение ierr, а второй – соответствующее сообщение об ошибке (полученное через FormatMessage()), и затем вызывает PyErr_SetObject(PyExc_WindowsError, object). Эта функция всегда возвращает NULL. Доступность: Windows.

PyObject* PyErr_SetExcFromWindowsErr(PyObject *type, int ierr)
Возвращаемое значение: всегда NULL.

Аналогично PyErr_SetFromWindowsErr(), с дополнительным параметром, указывающим тип возбуждаемого исключения. Доступность: Windows.

PyObject* PyErr_SetFromWindowsErrWithFilename(int ierr, const char *filename)
Возвращаемое значение: всегда NULL.

Похожа на PyErr_SetFromWindowsErr(), с дополнительным поведением: если filename не равен NULL, он передаётся конструктору WindowsError в качестве третьего параметра. Доступность: Windows.

PyObject* PyErr_SetExcFromWindowsErrWithFilename(PyObject *type, int ierr, char *filename)
Возвращаемое значение: всегда NULL.

Аналогично PyErr_SetFromWindowsErrWithFilename(), с дополнительным параметром, указывающим тип возбуждаемого исключения. Доступность: Windows.

void PyErr_BadInternalCall()
Это сокращённая форма для PyErr_SetString(PyExc_SystemError, message), где message указывает, что внутренняя операция (например, функция Python/C API) была вызвана с недопустимым аргументом. В основном используется внутри.
int PyErr_WarnEx(PyObject *category, char *message, int stacklevel)

Выдаёт предупреждение. Аргумент category – это категория предупреждения (см. ниже) или NULL; аргумент message – строка сообщения. stacklevel – положительное число, задающее количество кадров стека; предупреждение будет выдано из строки кода, выполняющейся в этом кадре стека. stacklevel, равный 1, соответствует функции, вызывающей PyErr_WarnEx(), 2 – функции, вызвавшей её, и так далее.

Обычно эта функция выводит предупреждение в sys.stderr; однако возможно, что пользователь указал превращать предупреждения в ошибки, и в этом случае будет вызвано исключение. Также возможно, что функция вызывает исключение из-за проблемы в механизме предупреждений (реализация импортирует модуль warnings для выполнения основной работы). Возвращаемое значение – 0, если исключение не возникло, или -1, если возникло. (Невозможно определить, было ли предупреждение фактически выведено, а также причину исключения; это сделано намеренно.) Если возникло исключение, вызывающий код должен выполнить обычную обработку исключений (например, Py_DECREF() для владеемых ссылок и вернуть значение ошибки).

Категории предупреждений должны быть подклассами Warning; категория предупреждения по умолчанию – RuntimeWarning. Стандартные категории предупреждений Python доступны как глобальные переменные, имена которых – PyExc_, за которым следует имя исключения Python. Они имеют тип PyObject*; все они являются объектами классов. Их имена: PyExc_Warning, PyExc_UserWarning, PyExc_UnicodeWarning, PyExc_DeprecationWarning, PyExc_SyntaxWarning, PyExc_RuntimeWarning и PyExc_FutureWarning. PyExc_Warning является подклассом PyExc_Exception; остальные категории предупреждений являются подклассами PyExc_Warning.

Подробнее об управлении предупреждениями см. документацию модуля warnings и опцию -W в документации командной строки. C API для управления предупреждениями не существует.

int PyErr_WarnExplicit(PyObject *category, const char *message, const char *filename, int lineno, const char *module, PyObject *registry)
Выдаёт предупреждение с явным контролем всех атрибутов предупреждения. Это простая обёртка вокруг функции Python warnings.warn_explicit(), см. описание там. Аргументы module и registry могут быть установлены в NULL для получения эффекта по умолчанию, как описано там.
int PyErr_CheckSignals()

Эта функция взаимодействует с обработкой сигналов Python. Она проверяет, был ли отправлен сигнал процессам, и если да, вызывает соответствующий обработчик сигнала. Если модуль signal поддерживается, может быть вызван обработчик сигнала, написанный на Python. Во всех случаях действие по умолчанию для SIGINT – возбуждение исключения KeyboardInterrupt. Если исключение возбуждено, устанавливается индикатор ошибки, и функция возвращает -1; в противном случае функция возвращает 0. Индикатор ошибки может быть сброшен или не сброшен, если он был установлен ранее.

void PyErr_SetInterrupt()

Эта функция имитирует поступление сигнала SIGINT – при следующем вызове PyErr_CheckSignals() будет возбуждено исключение KeyboardInterrupt. Может быть вызвана без захвата блокировки интерпретатора.

int PySignal_SetWakeupFd(int fd)
Эта вспомогательная функция задаёт файловый дескриптор, в который будет записан байт '\0' при получении сигнала. Возвращает предыдущий такой файловый дескриптор. Значение -1 отключает эту возможность; это начальное состояние. Эквивалентно signal.set_wakeup_fd() в Python, но без проверки ошибок. fd должен быть корректным файловым дескриптором. Функцию следует вызывать только из главного потока.
PyObject* PyErr_NewException(char *name, PyObject *base, PyObject *dict)
Возвращаемое значение: новая ссылка.

Эта вспомогательная функция создаёт и возвращает новый объект исключения. Аргумент name должен задавать имя нового исключения – строку C в формате module.class. Аргументы base и dict обычно равны NULL. Функция создаёт объект класса, производного от Exception (на C доступен как PyExc_Exception).

Атрибут __module__ нового класса устанавливается в первую часть (до последней точки) аргумента name, а имя класса – в последнюю часть (после последней точки). Аргумент base можно использовать для указания альтернативных базовых классов; это может быть как один класс, так и кортеж классов. Аргумент dict можно использовать для указания словаря переменных и методов класса.

void PyErr_WriteUnraisable(PyObject *obj)

Эта вспомогательная функция выводит предупреждение в sys.stderr, когда исключение установлено, но интерпретатор не может его фактически возбудить. Используется, например, когда исключение возникает в методе __del__().

Функция вызывается с одним аргументом obj, который идентифицирует контекст, в котором возникло не вызываемое исключение. В сообщении предупреждения будет выведено repr от obj.

Объекты исключенийException Objects

PyObject* PyException_GetTraceback(PyObject *ex)
Возвращает traceback, связанный с исключением, как новую ссылку, доступную из Python через __traceback__. Если traceback не связан, возвращает NULL.
int PyException_SetTraceback(PyObject *ex, PyObject *tb)
Устанавливает traceback, связанный с исключением, в tb. Используйте Py_None для его очистки.
PyObject* PyException_GetContext(PyObject *ex)
Возвращает контекст (другой экземпляр исключения, при обработке которого было возбуждено ex), связанный с исключением, как новую ссылку, доступную из Python через __context__. Если контекст не связан, возвращает NULL.
void PyException_SetContext(PyObject *ex, PyObject *ctx)
Устанавливает контекст, связанный с исключением, в ctx. Используйте NULL для его очистки. Проверка типа на то, что ctx является экземпляром исключения, не выполняется. Функция забирает ссылку на ctx.
PyObject* PyException_GetCause(PyObject *ex)
Возвращает причину (другой экземпляр исключения, заданный через raise ... from ...) для этого исключения в виде новой ссылки, как это доступно из Python через __cause__. Если причина не задана, возвращается NULL.
void PyException_SetCause(PyObject *ex, PyObject *ctx)
Устанавливает причину, связанную с исключением, в ctx. Используйте NULL, чтобы очистить её. Проверка типа на то, что ctx является экземпляром исключения, не выполняется. Это похищает ссылку на ctx.

Объекты исключений UnicodeUnicode Exception Objects

Следующие функции используются для создания и изменения исключений Unicode из C.

PyObject* PyUnicodeDecodeError_Create(const char *encoding, const char *object, Py_ssize_t length, Py_ssize_t start, Py_ssize_t end, const char *reason)
Создаёт объект UnicodeDecodeError с атрибутами encoding, object, length, start, end и reason.
PyObject* PyUnicodeEncodeError_Create(const char *encoding, const Py_UNICODE *object, Py_ssize_t length, Py_ssize_t start, Py_ssize_t end, const char *reason)
Создаёт объект UnicodeEncodeError с атрибутами encoding, object, length, start, end и reason.
PyObject* PyUnicodeTranslateError_Create(const Py_UNICODE *object, Py_ssize_t length, Py_ssize_t start, Py_ssize_t end, const char *reason)
Создаёт объект UnicodeTranslateError с атрибутами object, length, start, end и reason.
PyObject* PyUnicodeDecodeError_GetEncoding(PyObject *exc)
PyObject* PyUnicodeEncodeError_GetEncoding(PyObject *exc)
Возвращает атрибут encoding указанного объекта исключения.
PyObject* PyUnicodeDecodeError_GetObject(PyObject *exc)
PyObject* PyUnicodeEncodeError_GetObject(PyObject *exc)
PyObject* PyUnicodeTranslateError_GetObject(PyObject *exc)
Возвращает атрибут object указанного объекта исключения.
int PyUnicodeDecodeError_GetStart(PyObject *exc, Py_ssize_t *start)
int PyUnicodeEncodeError_GetStart(PyObject *exc, Py_ssize_t *start)
int PyUnicodeTranslateError_GetStart(PyObject *exc, Py_ssize_t *start)
Получает атрибут start заданного объекта исключения и помещает его в *start. start не должен быть NULL. Возвращает 0 в случае успеха, -1 при неудаче.
int PyUnicodeDecodeError_SetStart(PyObject *exc, Py_ssize_t start)
int PyUnicodeEncodeError_SetStart(PyObject *exc, Py_ssize_t start)
int PyUnicodeTranslateError_SetStart(PyObject *exc, Py_ssize_t start)
Устанавливает атрибут start указанного объекта исключения в значение start. Возвращает 0 при успехе, -1 при ошибке.
int PyUnicodeDecodeError_GetEnd(PyObject *exc, Py_ssize_t *end)
int PyUnicodeEncodeError_GetEnd(PyObject *exc, Py_ssize_t *end)
int PyUnicodeTranslateError_GetEnd(PyObject *exc, Py_ssize_t *end)
Получает атрибут end заданного объекта исключения и помещает его в *end. end не должен быть NULL. Возвращает 0 в случае успеха, -1 при неудаче.
int PyUnicodeDecodeError_SetEnd(PyObject *exc, Py_ssize_t end)
int PyUnicodeEncodeError_SetEnd(PyObject *exc, Py_ssize_t end)
int PyUnicodeTranslateError_SetEnd(PyObject *exc, Py_ssize_t end)
Устанавливает атрибут end указанного объекта исключения в end. Возвращает 0 в случае успеха, -1 при ошибке.
PyObject* PyUnicodeDecodeError_GetReason(PyObject *exc)
PyObject* PyUnicodeEncodeError_GetReason(PyObject *exc)
PyObject* PyUnicodeTranslateError_GetReason(PyObject *exc)
Возвращает атрибут reason указанного объекта исключения.
int PyUnicodeDecodeError_SetReason(PyObject *exc, const char *reason)
int PyUnicodeEncodeError_SetReason(PyObject *exc, const char *reason)
int PyUnicodeTranslateError_SetReason(PyObject *exc, const char *reason)
Устанавливает атрибут reason указанного объекта исключения в значение reason. Возвращает 0 в случае успеха, -1 в случае ошибки.

Управление рекурсиейRecursion Control

Эти две функции предоставляют способ выполнения безопасных рекурсивных вызовов на уровне C как в ядре, так и в модулях расширения. Они необходимы, если рекурсивный код не обязательно вызывает код Python (который автоматически отслеживает свою глубину рекурсии).

int Py_EnterRecursiveCall(char *where)

Отмечает точку, в которой будет выполнен рекурсивный вызов на уровне C.

Если определён USE_STACKCHECK, эта функция проверяет, не переполнился ли стек ОС, с помощью PyOS_CheckStack(). Если это так, она устанавливает MemoryError и возвращает ненулевое значение.

Затем функция проверяет, достигнут ли лимит рекурсии. Если это так, устанавливается RuntimeError и возвращается ненулевое значение. В противном случае возвращается ноль.

where должна быть строкой, например " in instance check", которая будет добавлена к сообщению RuntimeError, вызванному пределом глубины рекурсии.

void Py_LeaveRecursiveCall()
Завершает Py_EnterRecursiveCall(). Должен вызываться один раз для каждого успешного вызова Py_EnterRecursiveCall().

Стандартные исключенияStandard Exceptions

Все стандартные исключения Python доступны как глобальные переменные, имена которых состоят из PyExc_, за которым следует имя исключения Python. Они имеют тип PyObject*; все они являются объектами классов. Для полноты картины, вот все переменные:

Имя в C Имя в Python Примечания
PyExc_BaseException BaseException (1)
PyExc_Exception исключение (1)
PyExc_ArithmeticError ArithmeticError (1)
PyExc_LookupError LookupError (1)
PyExc_AssertionError AssertionError  
PyExc_AttributeError AttributeError  
PyExc_EOFError EOFError  
PyExc_EnvironmentError EnvironmentError (1)
PyExc_FloatingPointError FloatingPointError  
PyExc_IOError IOError  
PyExc_ImportError ImportError  
PyExc_IndexError IndexError  
PyExc_KeyError KeyError  
PyExc_KeyboardInterrupt KeyboardInterrupt  
PyExc_MemoryError MemoryError  
PyExc_NameError NameError  
PyExc_NotImplementedError NotImplementedError  
PyExc_OSError OSError  
PyExc_OverflowError OverflowError  
PyExc_ReferenceError ReferenceError (2)
PyExc_RuntimeError RuntimeError  
PyExc_SyntaxError SyntaxError  
PyExc_SystemError SystemError  
PyExc_SystemExit SystemExit  
PyExc_TypeError TypeError  
PyExc_ValueError ValueError  
PyExc_WindowsError WindowsError (3)
PyExc_ZeroDivisionError ZeroDivisionError  

Примечания:

  1. Это базовый класс для других стандартных исключений.
  2. То же самое, что weakref.ReferenceError.
  3. Определён только в Windows; код, использующий это, должен проверять, определён ли макрос препроцессора MS_WINDOWS.