异常处理 — Python 文档

来自菜鸟教程
Python/docs/2.7/c-api/exceptions
跳转至:导航、​搜索

异常处理

本章中描述的函数将让您处理和引发 Python 异常。 了解 Python 异常处理的一些基础知识很重要。 它的工作方式有点像 Unix errno 变量:上次发生的错误有一个全局指示器(每个线程)。 大多数函数在成功时不会清除它,但会设置它以指示失败时错误的原因。 大多数函数也返回一个错误指示符,通常是 NULL 如果它们应该返回一个指针,或者 -1 如果它们返回一个整数(例外:PyArg_*() 函数返回 [ X193X] 表示成功,0 表示失败)。

当一个函数因为它调用的某个函数失败而必须失败时,它通常不设置错误指示器; 它调用的函数已经设置了它。 它负责处理错误和清除异常,或者在清理它持有的任何资源(例如对象引用或内存分配)后返回; 如果它不准备处理错误,它应该 not 继续正常。 如果由于错误而返回,重要的是向调用者表明已设置错误。 如果错误没有得到处理或小心传播,对 Python/C API 的额外调用可能不会按预期运行,并且可能会以神秘的方式失败。

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

void PyErr_PrintEx(int set_sys_last_vars)

将标准回溯打印到 sys.stderr 并清除错误指示器。 除非错误是SystemExit。 在这种情况下,不会打印回溯,Python 进程将退出,并显示 SystemExit 实例指定的错误代码。

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

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

void PyErr_Print()
PyErr_PrintEx(1) 的别名。
PyObject *PyErr_Occurred()

测试是否设置了错误指示灯。 如果设置,则返回异常 type(最后一次调用 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 中的异常匹配,则返回 true。 如果 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。 如果设置了它,它将被清除,并且您拥有对检索到的每个对象的引用。 即使类型对象不是,值和回溯对象也可能是 NULL

笔记

该函数通常只被需要处理异常的代码或需要临时保存和恢复错误指示器的代码使用。

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

从三个对象设置错误指示器。 如果错误指示器已设置,则首先将其清除。 如果对象为 NULL,则清除错误指示符。 不要传递 NULL 类型和非 NULL 值或回溯。 异常类型应该是一个类。 不要传递无效的异常类型或值。 (违反这些规则会在以后导致一些微妙的问题。)这个调用会带走对每个对象的引用:在调用之前你必须拥有对每个对象的引用,在调用之后你不再拥有这些引用。 (如果您不明白这一点,请不要使用此功能。 我警告过你。)

笔记

该函数一般只用于需要临时保存和恢复错误指示器的代码; 使用 PyErr_Fetch() 保存当前异常状态。

void PyErr_SetString(PyObject *type, const char *message)
这是设置错误指示器的最常用方法。 第一个参数指定异常类型; 它通常是标准例外之一,例如 PyExc_RuntimeError。 你不需要增加它的引用计数。 第二个参数是错误信息; 它被转换为字符串对象。
void PyErr_SetObject(PyObject *type, PyObject *value)
此函数类似于 PyErr_SetString() 但允许您为异常的“值”指定任意 Python 对象。
PyObject *PyErr_Format(PyObject *exception, const char *format, ...)
此函数设置错误指示符并返回 NULLexception 应该是一个 Python 异常类。 format 和后续参数帮助格式化错误信息; 它们具有与 PyString_FromFormat() 中相同的含义和值。
void PyErr_SetNone(PyObject *type)
这是 PyErr_SetObject(type, Py_None) 的简写。
int PyErr_BadArgument()
这是 PyErr_SetString(PyExc_TypeError, message) 的简写,其中 message 表示使用非法参数调用了内置操作。 它主要供内部使用。
PyObject *PyErr_NoMemory()
这是 PyErr_SetNone(PyExc_MemoryError) 的简写; 它返回 NULL,因此对象分配函数可以在内存不足时写入 return PyErr_NoMemory();
PyObject *PyErr_SetFromErrno(PyObject *type)
这是一个方便的函数,可以在 C 库函数返回错误并设置 C 变量 errno 时引发异常。 它构造一个元组对象,其第一项是整数 errno 值,第二项是相应的错误消息(从 strerror() 中获取),然后调用 PyErr_SetObject(type, object)。 在 Unix 上,当 errno 值为 EINTR 时,表示系统调用中断,这将调用 PyErr_CheckSignals(),如果设置了错误指示符,则将其设置为那。 该函数始终返回 NULL,因此系统调用周围的包装函数可以在系统调用返回错误时写入 return PyErr_SetFromErrno(type);
PyObject *PyErr_SetFromErrnoWithFilenameObject(PyObject *type, PyObject *filenameObject)
PyErr_SetFromErrno() 类似,附加的行为是如果 filenameObject 不是 NULL,则将其传递给 type 的构造函数作为第三个参数。 在IOErrorOSError等异常情况下,用于定义异常实例的filename属性。
PyObject *PyErr_SetFromErrnoWithFilename(PyObject *type, const char *filename)
类似于 PyErr_SetFromErrnoWithFilenameObject(),但文件名以 C 字符串形式给出。
PyObject *PyErr_SetFromWindowsErr(int ierr)
这是提高WindowsError的便利功能。 如果使用 0ierr 调用,则使用调用 GetLastError() 返回的错误代码。 它调用 Win32 函数 FormatMessage() 来检索由 ierrGetLastError() 给出的错误代码的 Windows 描述,然后构造一个元组对象,其第一项是 ierr 值,其第二项是对应的错误信息(取自 FormatMessage()),然后调用 PyErr_SetObject(PyExc_WindowsError, object)。 此函数始终返回 NULL。 可用性:Windows。
PyObject *PyErr_SetExcFromWindowsErr(PyObject *type, int ierr)

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

2.3 版中的新功能。

PyObject *PyErr_SetFromWindowsErrWithFilenameObject(int ierr, PyObject *filenameObject)
类似于 PyErr_SetFromWindowsErr(),附加的行为是,如果 filenameObject 不是 NULL,它会作为一个传递给 WindowsError 的构造函数第三个参数。 可用性:Windows。
PyObject *PyErr_SetFromWindowsErrWithFilename(int ierr, const char *filename)
类似于 PyErr_SetFromWindowsErrWithFilenameObject(),但文件名以 C 字符串形式给出。 可用性:Windows。
PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject(PyObject *type, int ierr, PyObject *filename)

类似于 PyErr_SetFromWindowsErrWithFilenameObject(),附加参数指定要引发的异常类型。 可用性:Windows。

2.3 版中的新功能。

PyObject *PyErr_SetExcFromWindowsErrWithFilename(PyObject *type, int ierr, const char *filename)

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

2.3 版中的新功能。

void PyErr_BadInternalCall()
这是 PyErr_SetString(PyExc_SystemError, message) 的简写,其中 message 表示内部操作(例如 一个 Python/C API 函数)被非法参数调用。 它主要供内部使用。
int PyErr_WarnEx(PyObject *category, char *message, int stacklevel)

发出警告消息。 category 参数是一个警告类别(见下文)或 NULLmessage 参数是一个消息字符串。 stacklevel 是一个正数,给出堆栈帧的数量; 警告将从该堆栈帧中当前正在执行的代码行发出。 stacklevel 为 1 是调用 PyErr_WarnEx() 的函数,2 是上面的函数,依此类推。

此函数通常会向 sys.stderr 打印警告消息; 然而,也有可能用户已指定将警告转换为错误,在这种情况下,这将引发异常。 由于警告机制的问题,该函数也可能引发异常(实现导入 warnings 模块来完成繁重的工作)。 如果未引发异常,则返回值为 0,如果引发异常,则返回值为 -1。 (无法确定是否实际打印了警告消息,也无法确定异常的原因是什么;这是故意的。)如果引发异常,调用者应该进行正常的异常处理(例如, Py_DECREF() 拥有引用并返回错误值)。

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

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

int PyErr_Warn(PyObject *category, char *message)

发出警告消息。 category 参数是一个警告类别(见下文)或 NULLmessage 参数是一个消息字符串。 警告似乎是从调用 PyErr_Warn() 的函数发出的,等效于调用 PyErr_WarnEx()stacklevel 为 1。

已弃用; 使用 PyErr_WarnEx() 代替。

int PyErr_WarnExplicit(PyObject *category, const char *message, const char *filename, int lineno, const char *module, PyObject *registry)
发出警告消息,明确控制所有警告属性。 这是 Python 函数 warnings.warn_explicit() 的简单包装,请参阅此处了解更多信息。 moduleregistry 参数可以设置为 NULL 以获得那里描述的默认效果。
int PyErr_WarnPy3k(char *message, int stacklevel)

如果启用了 Py_Py3kWarningFlag 标志,则使用给定的 消息stacklevel 发出 DeprecationWarning

2.6 版中的新功能。

int PyErr_CheckSignals()
此函数与 Python 的信号处理交互。 它检查信号是否已发送到进程,如果是,则调用相应的信号处理程序。 如果支持 signal 模块,则可以调用用 Python 编写的信号处理程序。 在所有情况下,SIGINT 的默认效果是引发 KeyboardInterrupt 异常。 如果引发异常,则设置错误指示器并且函数返回 -1; 否则函数返回 0。 如果先前已设置,错误指示器可能会或可能不会被清除。
void PyErr_SetInterrupt()
此函数模拟 SIGINT 信号到达的效果——下次调用 PyErr_CheckSignals() 时,将引发 KeyboardInterrupt。 可以在不持有解释器锁的情况下调用它。
int PySignal_SetWakeupFd(int fd)

此实用程序函数指定一个文件描述符,每当接收到信号时,'\0' 字节将写入该文件描述符。 它返回以前的此类文件描述符。 值 -1 禁用该功能; 这是初始状态。 这相当于 Python 中的 signal.set_wakeup_fd(),但没有任何错误检查。 fd 应该是一个有效的文件描述符。 该函数只能从主线程调用。

2.6 版中的新功能。

PyObject *PyErr_NewException(char *name, PyObject *base, PyObject *dict)

此实用程序函数创建并返回一个新的异常类。 name 参数必须是新异常的名称,即 module.classname 形式的 C 字符串。 basedict 参数通常是 NULL。 这将创建一个从 Exception 派生的类对象(在 C 中可作为 PyExc_Exception 访问)。

新类的 __module__ 属性设置为 name 参数的第一部分(直到最后一个点),类名设置为最后一部分(最后一个点之后)点)。 base 参数可用于指定替代基类; 它可以只是一个类,也可以是一组类。 dict 参数可用于指定类变量和方法的字典。

PyObject *PyErr_NewExceptionWithDoc(char *name, char *doc, PyObject *base, PyObject *dict)

PyErr_NewException() 相同,除了新的异常类可以很容易地给出一个文档字符串:如果 doc 是非 NULL,它将被用作异常类的文档字符串。

2.7 版中的新功能。

void PyErr_WriteUnraisable(PyObject *obj)

当设置了异常但解释器不可能实际引发异常时,此实用程序函数会向 sys.stderr 打印一条警告消息。 例如,在 __del__() 方法中发生异常时使用。

使用单个参数 obj 调用该函数,该参数标识发生不可引发异常的上下文。 如果可能,obj 的 repr 将打印在警告消息中。

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)
创建一个 UnicodeDecodeError 对象,其属性为 encodingobjectlengthstartend ] 和 原因
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 对象,其属性为 encodingobjectlengthstartend ] 和 原因
PyObject *PyUnicodeTranslateError_Create(const Py_UNICODE *object, Py_ssize_t length, Py_ssize_t start, Py_ssize_t end, const char *reason)
创建一个 UnicodeTranslateError 对象,其属性为 objectlengthstartendreason ]。
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 属性并将其放入 *startstart 不能是 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 属性并将其放入 *endend 不能是 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


递归控制

这两个函数提供了一种在核心和扩展模块中在 C 级别执行安全递归调用的方法。 如果递归代码不一定调用 Python 代码(自动跟踪其递归深度),则需要它们。

int Py_EnterRecursiveCall(const char *where)

标记将要执行递归 C 级调用的点。

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

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

其中 应该是一个字符串,例如 " in instance check" 连接到由递归深度限制引起的 RuntimeError 消息。

void Py_LeaveRecursiveCall()
结束 Py_EnterRecursiveCall()。 对于 Py_EnterRecursiveCall() 的每次 successful 调用,必须调用一次。


标准例外

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

姓名 蟒蛇名称 笔记
PyExc_BaseException BaseException (1), (4)
PyExc_Exception Exception (1)
PyExc_StandardError StandardError (1)
PyExc_ArithmeticError ArithmeticError (1)
PyExc_AssertionError AssertionError
PyExc_AttributeError AttributeError
PyExc_BufferError BufferError
PyExc_EnvironmentError EnvironmentError (1)
PyExc_EOFError EOFError
PyExc_FloatingPointError FloatingPointError
PyExc_GeneratorExit GeneratorExit
PyExc_ImportError ImportError
PyExc_IndentationError IndentationError
PyExc_IndexError IndexError
PyExc_IOError IOError
PyExc_KeyError KeyError
PyExc_KeyboardInterrupt KeyboardInterrupt
PyExc_LookupError LookupError (1)
PyExc_MemoryError MemoryError
PyExc_NameError NameError
PyExc_NotImplementedError NotImplementedError
PyExc_OSError OSError
PyExc_OverflowError OverflowError
PyExc_ReferenceError ReferenceError (2)
PyExc_RuntimeError RuntimeError
PyExc_StopIteration StopIteration
PyExc_SyntaxError SyntaxError
PyExc_SystemError SystemError
PyExc_SystemExit SystemExit
PyExc_TabError TabError
PyExc_TypeError TypeError
PyExc_UnboundLocalError UnboundLocalError
PyExc_UnicodeDecodeError UnicodeDecodeError
PyExc_UnicodeEncodeError UnicodeEncodeError
PyExc_UnicodeError UnicodeError
PyExc_UnicodeTranslateError UnicodeTranslateError
PyExc_VMSError VMSError (5)
PyExc_ValueError ValueError
PyExc_WindowsError WindowsError (3)
PyExc_ZeroDivisionError ZeroDivisionError

笔记:

  1. 这是其他标准异常的基类。

  2. 这与 weakref.ReferenceError 相同。

  3. 仅在 Windows 上定义; 通过测试预处理器宏 MS_WINDOWS 的定义来保护使用它的代码。

  4. 2.5 版中的新功能。

  5. 仅在 VMS 上定义; 通过测试预处理器宏 __VMS 的定义来保护使用它的代码。


标准警告类别

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

姓名 蟒蛇名称 笔记
PyExc_Warning Warning (1)
PyExc_BytesWarning BytesWarning
PyExc_DeprecationWarning DeprecationWarning
PyExc_FutureWarning FutureWarning
PyExc_ImportWarning ImportWarning
PyExc_PendingDeprecationWarning PendingDeprecationWarning
PyExc_RuntimeWarning RuntimeWarning
PyExc_SyntaxWarning SyntaxWarning
PyExc_UnicodeWarning UnicodeWarning
PyExc_UserWarning UserWarning

笔记:

  1. 这是其他标准警告类别的基类。


字符串异常

在 2.6 版更改: 要引发或捕获的所有异常必须派生自 BaseException。 现在尝试引发字符串异常会引发 TypeError