Python/C API 异常处理

Python/C API 异常处理(部分)

Python/C API 中的异常处理与Unix系统中的errno 变量类似,每个线程都有一个全局的异常指示器,该指示器只记录最后一次发生的异常。大多数函数都不会在成功执行时清除该指示器,但会在异常发生时及时设置该指示器。大部分函数函数也都会返回一个标志来指示其执行过程中是否发生异常,如果函数的返回类型为指针,则返回NULL时表示有异常发生;若返回类型为整数,返回-1表示有异常发生(例外:PyArg_*() 函数返回1表示成功,0表示失败)。

若函数A调用函数B,并且当函数B发生异常必定导致函数A失败时,函数A不能再次设置异常指示器,因为函数B已经设置了。

异常指示器拥有同sys.exc_info()返回值相同的三个对象。

1 异常处理函数

  • void PyErr_PrintEx(int set_sys_last_vars)
  • void PyErr_Print() // set_sys_last_vars=1
    将标准traceback打印至sys.stderr,并且清除错误指示器。只有错误指示器被设置后才能调用这个函数,否则会造成严重的错误。如果参数set_sys_last_vars 不为0,则变量sys.last_typesys.last_valuesys.last_traceback 将会分别被设置为北大印异常对象的类型、值、traceback。

  • PyObject * PyErr_Occurred()
    返回borrowed引用。检查错误指示器是否被设置,是则返回异常type,否则返回NULL。因为是borrowed引用,所以不用调用Py_DECREF()
    注意:不要将返回值与一个特定的异常直接进行比较,要用PyErr_ExceptionMatches() 进行比较。

  • int PyErr_GiveExceptionMatches(PyObject *given, PyObject *exc)

  • int PyErr_ExceptionMatches(PyObject *exc) // given=PyErr_Occurred()
    比较given异常是否与exc匹配,后者只能在确实有异常发生时才能调用,否则会发生内存的非法访问。如果exc是一个class对象,则当given是exc的子类时返回true;如果exc为一个元组,则将given与exc中的每个成员进行匹配检查。

  • void PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
    在一些情况下,函数PyErr_Fetch() 的返回值可能是unnormalized(*exc是一个class对象,但*val不是该class的实例),该函数能够将*val实例化为exc类型,若*val已经被实例化为*exc类型,则该函数不会进行任何操作。将*normalization推迟是为了提高性能。
    注意:该函数不会将__traceback__设置到*val中,如果需要这么做,需要这么做

if (tb != NULL)
{
    PyException_SetTraceback(val, tb);
}
  • void PyErr_Clear()
    清除错误指示器, 如果错误指示器没有设置,则不会有任何影响。

  • void PyErr_Fetch(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback)
    从错误指示器中取回三个变量,并将其存入提供的参数中。如果错误指示器没有设置,三个参数将被设置为NULL;否则,错误指示器将会被清空并且调用者将获得三个对象的引用。即使type对象不为NULL,value对象和traceback对象也有可能为NULL。
    注意:当代码中要处理异常或需要保存异常指示器时,通常会调用该函数。

  • void PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
    将三个参数提供的信息设置到错误指示器中。若在这之前错误指示器已经被设置,则会先将其清除。如果被传入的对象为NULL,错误指示器将会被清除。不要将type==NULL && (value!=NULL || traceback!=NULL) 作为参数传入。参数type一定要有效且是一个class。
    警告:该函数会take away每个对象的引用,所以在调用之前,你一定要拥有每个对象的引用,调用之后,你就会失去它们。
    注意:在需要暂时设置异常指示器时可以调用该函数。

  • void PyErr_GetExcInfo(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback)
    获取刚捕获异常的信息(刚捕获的异常,非重新抛出的异常),返回每个对象的新的引用、每个对象都有可能为NULL。该函数不会改变异常信息状态。

  • void PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback)
    设置异常信息(刚捕获的异常,非重新抛出的异常)。该函数会steal参数的引用。若希望清除异常状态,可将NULL传给每个参数。

  • void PyErr_SetString(PyObject *type, const char *message)
    该函数是最常用 的错误指示器设置方式。第一个参数指定异常类型,其一般为一个标准异常类型(比如PyExc_RuntimeError),用户不需要增加其引用计数;第二个参数是错误信息,使用utf8编码。

  • void PyErr_SetObject(PyObject *type, PyObject *value)
    同PyErr_SetString()类似,可为异常对象设置任意的对象。

  • PyObject * PyErr_Format(PyObject *exception, const char *format, …)
    返回值一直为NULL。该函数设置函数指示器并返回NULL,参数exception要是一个Python异常类,参数format和其后的参数与函数PyUnicode_FromFormat() 中的参数有相同的含义,参数format为ASCII编码字符串。

  • void PyErr_SetNone(PyObject *type)
    –> PyErr_SetObject(type, Py_None)

  • void PyErr_BadArgument()
    –>PyErr_SetString(PyExc_TypeError, message),其中message为非法参数激活内置操作时的信息。

  • PyObject * PyErr_NoMemory()
    –>PyErr_SetNone(PyExc_MemoryError)
    返回值一直为NULL。可在发生分配内存失败时,作为返回值用 return PyErr_NoMemory()

  • PyObject * PyErr_SetFromErrno(PyObject *type)
    返回值一直为NULL。这其实是个转换函数,当C库函数返回错误并设置errno时,抛出一个异常。该函数会构造一个元组对象,其第一个值为整数errno,第二个值是对应的错误信息(从函数strerror() 函数获得),然后调用PyErr_SetObject(type, object)。在Unix系统中,当errno为EINTR时,表示信号中断了系统调用,该函数会调用PyErr_CheckSignals(),若该函数设置了错误指示器,则保留该错误指示器。因为该函数返回NULL,所以在系统API失败时可直接return PyErr_SetFromErrno(type)

  • PyObject * PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
    该函数是一个很方便抛出ImportError异常的函数。参数msg设置为异常信息字符串,参数name和path都可以为NULL,不为NULL时要设置为ImportError异常对应的name和path属性。

  • void PyErr_SyntaxLocationObject(PyObject *filename, int lineno, int col_offset)

  • void PyErr_SyntaxLocationEx(const char *filename, int lineno, int col_offset)
  • void PyErr_SyntaxLocation(const char *filename, int lineno)
    为当前异常设置对应的文件、行、偏移信息。

2 异常对象

  • PyObject * PyException_GetTraceback(PyObject *ex)
    返回当前异常对象traceback的一个新的引用,就像在Python代码中使用__traceback__一样。若当前没有traceback信息,则返回NULL。

  • int PyException_SetTraceback(PyObject *ex, PyObject *tb)
    将异常对象ex的traceback信息设置为tb,若tb为Py_None则可清除相应的traceback信息。

  • PyObject * PyException_GetContext(PyObject *ex)
    返回异常对象ex的山下文信息(在处理ex期间抛出的另一个异常实例),返回值为一个新的引用,就像在Python中使用__context__一样。若没有,则返回NULL。

  • void PyException_SetContext(PyObject *ex, PyObject *ctx)
    设置ex的context为ctx,若ctx则清除ex的context。该函数会steal参数ctx的引用。

  • PyObject * PyException_GetCause(PyObject *ex)
    返回一个异常对应的实例或None,就像在Python代码中使用__cause__一样。

  • void PyException_SetCause(PyObject *ex, PyObject *cause)
    将与异常关联的异常原因设置为参数cause,cause的引用会被steal,若cause为NULL则会清除对应的cause。


你可能感兴趣的:(PythonCAPI,api,异常处理)