Exception Handling

本章中描述的Function将使您能够处理和引发 Python 异常。了解 Python 异常处理的一些基础知识很重要。它的工作原理类似于 Unix errno变量:全局指示器(每个线程)指示最近发生的错误。大多数Function不会在成功时清除此错误,但会设置它以指示失败时错误的原因。大多数函数还会返回错误指示符,如果应该返回指针,则通常为* NULL *;如果返回整数,则通常为-1(exceptions:PyArg_*()函数返回1表示成功,0表示失败)。

当某个函数由于某个函数调用失败而必须失败时,通常不会设置错误指示符。它调用的Function已经设置好了。它负责处理错误并清除异常,或者负责清除其拥有的任何资源(例如对象引用或内存分配)后返回;如果它没有准备好处理错误,则应该continue 正常运行。如果由于错误而返回,则重要的是向呼叫者表明已设置了错误。如果未处理或未认真传播错误,则对 Python/C API 的其他调用可能无法正常运行,并且可能会以神秘方式失败。

错误指示符由与 Python 变量sys.exc_typesys.exc_valuesys.exc_traceback对应的三个 Python 对象组成。存在 API 函数以各种方式与错误指示符进行交互。每个线程都有一个单独的错误指示器。

  • 无效PyErr_PrintEx(int * set_sys_last_vars *)
    • 将标准回溯打印到sys.stderr,然后清除错误指示符。 除非 ,否则错误是SystemExit。在这种情况下,将不打印回溯,并且 Python 进程将退出,并返回SystemExit实例指定的错误代码。

设置错误指示器后,仅**调用此函数。否则会导致致命错误!

如果* set_sys_last_vars *不为零,则变量sys.last_typesys.last_valuesys.last_traceback将分别设置为打印异常的类型,值和回溯。

  • 无效PyErr_Print()

    • PyErr_PrintEx(1)的别名。
  • PyObject* PyErr_Occurred ( )

    • *返回值:借用参考。

测试是否设置了错误指示器。如果设置,则返回异常* type (对PyErr_Set*()函数之一或PyErr_Restore()的最后一次调用的第一个参数)。如果未设置,则返回 NULL *。您没有对返回值的引用,因此不需要Py_DECREF()

Note

不要将返回值与特定异常进行比较;改为使用PyErr_ExceptionMatches(),如下所示。 (比较很容易失败,因为在类异常的情况下,异常可能是实例而不是类,或者可能是预期异常的子类.)

  • int PyErr_ExceptionMatches(PyObject ** exc *)

    • 等效于PyErr_GivenExceptionMatches(PyErr_Occurred(), exc)。仅当实际设置了异常时才应调用此方法。如果没有引发异常,则会发生内存访问冲突。
  • int PyErr_GivenExceptionMatches(PyObject 已提供PyObject* exc *)

    • 如果* given 异常与 exc 中的异常匹配,则返回 true。如果 exc 是类对象,则当 given 是子类的实例时,它也会返回 true。如果 exc *是一个 Tuples,则将搜索该 Tuples 中的所有异常(并以递归方式在子 Tuples 中)以查找匹配项。
  • 无效PyErr_NormalizeException(PyObject exc,PyObject val,PyObject ** tb)

    • 在某些情况下,下面的PyErr_Fetch()返回的值可以是“未规范化的”,这意味着*exc是一个类对象,而*val不是同一类的实例。在这种情况下,可以使用该函数实例化该类。如果值已经标准化,则什么也不会发生。实施延迟归一化以提高性能。
  • 无效PyErr_Clear()

    • 清除错误指示器。如果未设置错误指示器,则无效。
  • 无效PyErr_Fetch(PyObject *** ptype PyObject* * pvalue *,PyObject *** ptraceback *)

    • 将错误指示符检索为三个已传递地址的变量。如果未设置错误指示符,请将所有三个变量设置为* NULL 。如果已设置,它将被清除,并且您拥有对检索到的每个对象的引用。即使类型对象不是,值和 traceback 对象也可能是 NULL *。

Note

此Function通常仅由需要处理异常的代码或需要临时保存和恢复错误指示符的代码使用。

  • 无效PyErr_Restore(PyObject 类型PyObject* 值*,PyObject *回溯)
    • 从三个对象设置错误指示器。如果错误指示器已经设置,则首先将其清除。如果对象为* NULL ,则清除错误指示符。不要传递 NULL 类型和非 NULL *值或回溯。异常类型应该是一个类。不要传递无效的异常类型或值。 (违反这些规则将在以后引起一些细微的问题.)此调用取消了对每个对象的引用:在调用之前,您必须拥有对每个对象的引用,而在调用之后,您将不再拥有这些引用。 (如果您不了解此Function,请不要使用此Function.我警告过您.)

Note

此Function通常仅用于需要临时保存和恢复错误指示符的代码。使用PyErr_Fetch()保存当前的异常状态。

  • 无效PyErr_SetString(PyObject *type ,const char message *)

    • 这是设置错误指示符的最常见方法。第一个参数指定异常类型;它通常是标准 exception 之一,例如PyExc_RuntimeError。您无需增加其引用计数。第二个参数是错误消息;它被转换为字符串对象。
  • 无效PyErr_SetObject(PyObject 类型PyObject* 值*)

    • 此函数类似于PyErr_SetString(),但允许您为异常的“值”指定任意 Python 对象。
  • PyObject * PyErr_Format(PyObject *exception ,const char format *,...)

    • 返回值:始终为 NULL.

此函数设置错误指示符并返回* NULL *。 * exception *应该是 Python 异常类。 * format *和后续参数有助于格式化错误消息;它们的含义和值与PyString_FromFormat()相同。

  • 无效PyErr_SetNone(PyObject *类型)

    • 这是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();

这是一个便利函数,可在 C 库函数返回错误并设置 C 变量errno时引发异常。它构造一个 Tuples 对象,其第一项是整数errno值,而第二项是相应的错误消息(从strerror()得到),然后调用PyErr_SetObject(type, object)。在 Unix 上,当errno值为EINTR时(表示系统调用已break),它将调用PyErr_CheckSignals(),如果设置了错误指示符,则将其设置为该值。该函数始终返回* NULL *,因此当系统调用返回错误时,围绕系统调用的包装器函数可以写入return PyErr_SetFromErrno(type);

  • PyObject * PyErr_SetFromErrnoWithFilenameObject(PyObject 类型PyObject* 文件名对象*)

    • PyErr_SetFromErrno()相似,另外的行为是,如果* filenameObject 不是 NULL ,它将作为第三个参数传递给 type *的构造函数。对于诸如IOErrorOSError之类的异常,它用于定义异常实例的filename属性。
  • PyObject * PyErr_SetFromErrnoWithFilename(PyObject *type ,const char filename *)

    • 返回值:始终为 NULL.

PyErr_SetFromErrnoWithFilenameObject()相似,但文件名以 C 字符串形式给出。

  • PyObject * PyErr_SetFromWindowsErr(int * ierr *)
    • 返回值:始终为 NULL.

这是提高WindowsError的便捷Function。如果以0的* ierr 进行调用,则会使用GetLastError()的调用返回的错误代码。它调用 Win32 函数FormatMessage()来检索 ierr GetLastError()给定的错误代码的 Windows 描述,然后构造一个 Tuples 对象,其第一项为 ierr 值,第二项为相应的错误消息(从FormatMessage()得到),然后调用PyErr_SetObject(PyExc_WindowsError, object)。此函数始终返回 NULL *。可用性:Windows。

  • PyObject * PyErr_SetExcFromWindowsErr(PyObject ** type *,int * ierr *)
    • 返回值:始终为 NULL.

PyErr_SetFromWindowsErr()相似,带有一个附加参数,指定要引发的异常类型。可用性:Windows。

2.3 版的新Function。

  • PyObject * PyErr_SetFromWindowsErrWithFilenameObject(int * ierr *,PyObject ** filenameObject *)

    • PyErr_SetFromWindowsErr()相似,另外的行为是,如果* filenameObject 不是 NULL *,它将作为第三个参数传递给WindowsError的构造函数。可用性:Windows。
  • PyObject * PyErr_SetFromWindowsErrWithFilename(int * ierr *,const char ** filename *)

    • 返回值:始终为 NULL.

PyErr_SetFromWindowsErrWithFilenameObject()相似,但文件名以 C 字符串形式给出。可用性:Windows。

2.3 版的新Function。

  • PyObject * PyErr_SetExcFromWindowsErrWithFilename(PyObject **type ,int * ierr ,const char filename *)
    • 返回值:始终为 NULL.

PyErr_SetFromWindowsErrWithFilename()相似,带有一个附加参数,指定要引发的异常类型。可用性:Windows。

2.3 版的新Function。

  • 无效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 是其之上的函数,依此类推。

此Function通常将警告消息打印到* sys.stderr *;但是,用户也可能已指定警告将变为错误,在这种情况下,这将引发异常。由于警告机制存在问题,该函数还可能引发异常(该实现会导入warnings模块来执行繁重的工作)。如果未引发异常,则返回值为0;如果引发异常,则返回值为-1。 (无法确定是否实际打印警告消息,也不知道异常的原因;这是有意的.)如果引发异常,则调用方应执行其常规异常处理(例如,Py_DECREF()拥有的引用)并返回错误值)。

警告类别必须是PyExc_Warning的子类; PyExc_WarningPyExc_Exception的子类;默认警告类别为PyExc_RuntimeWarning。标准的 Python 警告类别可用作全局变量,其名称在标准警告类别处枚举。

有关警告控制的信息,请参阅命令行文档中warnings模块的文档和-W选项。没有用于警告控制的 C API。

  • int PyErr_Warn(PyObject 类别,char* 消息*)
    • 发出警告消息。 * category 参数是警告类别(请参见下文)或 NULL *; * message 参数是一个消息字符串。该警告似乎是由调用PyErr_Warn()的函数发出的,等效于 stacklevel *为 1 的调用PyErr_WarnEx()

不推荐使用;请改用PyErr_WarnEx()

  • 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_WarnPy3k(char ** message *,int * stacklevel *)

    • 如果启用了Py_Py3kWarningFlag标志,则使用给定的* message stacklevel *发出DeprecationWarning

2.6 版的新Function。

  • int PyErr_CheckSignals()
    • 此函数与 Python 的 signal 处理交互。它检查是否已将 signal 发送到进程,如果已发送,则调用相应的 signal 处理程序。如果支持signal模块,则可以调用用 Python 编写的 signal 处理程序。在所有情况下,SIGINT的默认效果是引发KeyboardInterrupt异常。如果引发异常,则设置错误指示符,并且该函数返回-1;否则函数返回0。如果错误指示器是先前设置的,则可能会清除,也可能不会清除。
  • 无效PyErr_SetInterrupt()
  • int PySignal_SetWakeupFd(int * fd *)
    • 该 Util 函数指定一个文件 Descriptors,每当接收到 signal 时,便会将'\0'字节写入该文件 Descriptors。它返回先前的此类文件 Descriptors。值-1禁用该Function;这是初始状态。这等效于 Python 中的signal.set_wakeup_fd(),但没有任何错误检查。 * fd *应该是有效的文件 Descriptors。该函数只能从主线程调用。

2.6 版的新Function。

该 Util 函数创建并返回一个新的异常类。 * name *参数必须是新异常的名称,格式为module.classname的 C 字符串。 * base dict 参数通常是 NULL *。这将创建一个从Exception派生的类对象(在 C 中可以passPyExc_Exception访问)。

新类的__module__属性设置为* name *参数的第一部分(直到最后一个点),而类名则设置为最后一部分(在最后一个点之后)。 * base *参数可用于指定备用 Base Class;它既可以是一个类,也可以是一组 Tuples。 * dict *参数可用于指定类变量和方法的字典。

  • PyObject * PyErr_NewExceptionWithDoc(char *name ,char doc *,PyObject *base PyObject dict *)
    • 返回值:新参考.

PyErr_NewException()相同,不同之处在于可以轻松为新的异常类提供 docstring:如果* doc 为非 NULL *,它将用作异常类的 docstring。

2.7 版的新Function。

  • 无效PyErr_WriteUnraisable(PyObject ** obj *)
    • 设置了异常后,此 Util 函数会将警告消息打印到sys.stderr,但解释器实际上无法引发该异常。例如,在del()方法中发生异常时使用。

该函数使用单个参数* obj 进行调用,该参数标识发生了无法提出的异常的上下文。如果可能, obj *的代表将打印在警告消息中。

Unicode 异常对象

以下函数用于从 C 创建和修改 Unicode 异常。

  • PyObject * PyUnicodeDecodeError_Create(const char *encoding ,const char object *,Py_ssize_t * length *,Py_ssize_t * start *,Py_ssize_t * end *,const char ** reason *)

    • 使用属性* encoding object length start end reason *创建一个UnicodeDecodeError对象。
  • 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 *)

    • 使用属性* encoding object length start end reason *创建一个UnicodeEncodeError对象。
  • PyObject * PyUnicodeTranslateError_Create(const Py_UNICODE **object *,Py_ssize_t * length ,Py_ssize_t * start ,Py_ssize_t * end ,const char 原因)

    • 使用属性* object length start end reason *创建一个UnicodeTranslateError对象。
  • 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(const char ** where *)
    • 标记将要执行递归 C 级调用的点。

如果定义了USE_STACKCHECK,则此函数使用PyOS_CheckStack()检查 os 堆栈是否溢出。在这种情况下,它将设置MemoryError并返回非零值。

然后,该函数检查是否达到了递归限制。在这种情况下,将设置RuntimeError并返回非零值。否则,返回零。

  • where *应该是由递归深度限制引起的字符串,例如" in instance check"要与RuntimeError消息串联。

Standard Exceptions

所有标准 Python 异常都可以用作全局变量,其名称为PyExc_,后跟 Python 异常名称。它们的类型为PyObject*;它们都是类对象。为了完整起见,以下是所有变量:

C NamePython NameNotes
PyExc_BaseExceptionBaseException(1), (4)
PyExc_ExceptionException(1)
PyExc_StandardErrorStandardError(1)
PyExc_ArithmeticErrorArithmeticError(1)
PyExc_AssertionErrorAssertionError
PyExc_AttributeErrorAttributeError
PyExc_BufferErrorBufferError
PyExc_EnvironmentErrorEnvironmentError(1)
PyExc_EOFErrorEOFError
PyExc_FloatingPointErrorFloatingPointError
PyExc_GeneratorExitGeneratorExit
PyExc_ImportErrorImportError
PyExc_IndentationErrorIndentationError
PyExc_IndexErrorIndexError
PyExc_IOErrorIOError
PyExc_KeyErrorKeyError
PyExc_KeyboardInterruptKeyboardInterrupt
PyExc_LookupErrorLookupError(1)
PyExc_MemoryErrorMemoryError
PyExc_NameErrorNameError
PyExc_NotImplementedErrorNotImplementedError
PyExc_OSErrorOSError
PyExc_OverflowErrorOverflowError
PyExc_ReferenceErrorReferenceError(2)
PyExc_RuntimeErrorRuntimeError
PyExc_StopIterationStopIteration
PyExc_SyntaxErrorSyntaxError
PyExc_SystemErrorSystemError
PyExc_SystemExitSystemExit
PyExc_TabErrorTabError
PyExc_TypeErrorTypeError
PyExc_UnboundLocalErrorUnboundLocalError
PyExc_UnicodeDecodeErrorUnicodeDecodeError
PyExc_UnicodeEncodeErrorUnicodeEncodeError
PyExc_UnicodeErrorUnicodeError
PyExc_UnicodeTranslateErrorUnicodeTranslateError
PyExc_VMSErrorVMSError(5)
PyExc_ValueErrorValueError
PyExc_WindowsErrorWindowsError(3)
PyExc_ZeroDivisionErrorZeroDivisionError

Notes:

  • 这是其他标准异常的 Base Class。

  • 这与weakref.ReferenceError相同。

  • 仅在 Windows 上定义;pass测试定义了预处理程序宏MS_WINDOWS来保护使用此代码的代码。

  • 2.5 版的新Function。

  • 仅在 VMS 上定义;pass测试定义了预处理程序宏__VMS来保护使用此代码的代码。

标准警告类别

所有标准的 Python 警告类别都可以用作全局变量,其名称为PyExc_,后跟 Python 异常名称。它们的类型为PyObject*;它们都是类对象。为了完整起见,以下是所有变量:

C NamePython NameNotes
PyExc_WarningWarning(1)
PyExc_BytesWarningBytesWarning
PyExc_DeprecationWarningDeprecationWarning
PyExc_FutureWarningFutureWarning
PyExc_ImportWarningImportWarning
PyExc_PendingDeprecationWarningPendingDeprecationWarning
PyExc_RuntimeWarningRuntimeWarning
PyExc_SyntaxWarningSyntaxWarning
PyExc_UnicodeWarningUnicodeWarning
PyExc_UserWarningUserWarning

Notes:

  • 这是其他标准警告类别的 Base Class。

String Exceptions

在 2.6 版中更改:引发或捕获的所有异常都必须来自BaseException。现在try引发字符串异常会引发TypeError