用 C 扩展 Python:将 PyStringObject 转换为 PyIntObject

Extending Python with C: Convert PyStringObject to PyIntObject

用CPython 2.7,可以PyStringObject object be converted directly to a PyIntObject吗?

目前,我使用两个函数将 Python 字符串转换为 Python 整数,PyString_AsString and PyInt_FromString:

if (PyString_Check(pObj)) {
    /* Convert the string literal to an integer */
    pVal = PyInt_FromString(PyString_AsString(pObj), NULL, 10);
    printf(" From string: ");
    PyObject_Print(pVal, stdout, Py_PRINT_RAW);
    printf("\n");
} else if (PyInt_Check(pObj)) {
    pVal = pObj;
} else {
    PyErr_SetString(PyExc_TypeError, "list items must be integer string literals or integers");
    return NULL;
}

这很好用,但我想知道是否可以一步完成转换?

我认为这不会更容易完成 - 您可以使用字符串作为参数调用 int,但它会是 as contrived


请注意,您没有检查 pVal 的 return 值 - 如果字符串无法转换为整数,则 NULL 被 returned 并设置异常.

其实你可以直接调用 PyInt_Type with PyObject_CallFunctionObjArgs:

pVal = PyObject_CallFunctionObjArgs((PyObject *)&PyInt_Type, pObj, NULL);

但是您需要检查 returned pVal NULL。你说 "This works fine" 但如果你使用 "a" 之类的东西(Python String not C char!)作为 pObj 怎么办?我猜这会在您调用 PyObject_Print.

时出现段错误

通常您需要检查所有 return 值,以防万一出现问题。否则你可能 运行 陷入各种麻烦,例如当你将 NULL 传递给其他函数(分段错误)或 return 设置异常时的值(SystemError)。此外,您的引用计数取决于分支机构是不同的。您可以稍后在代码中处理它,但通常您可以只增加第二个分支中的引用计数,这样您以后就不需要额外的 if 了。所以我建议使用:

if (PyString_Check(pObj)) {
    /* Convert the string literal to an integer */
    pVal = PyObject_CallFunctionObjArgs((PyObject *)&PyInt_Type, pObj, NULL);
    if (pVal == NULL) {
        return NULL;
    }
    printf(" From string: ");
    PyObject_Print(pVal, stdout, Py_PRINT_RAW);  # <-- can this fail?
    printf("\n");
} else if (PyInt_Check(pObj)) {
    pVal = pObj;
    /* Increment the reference count so it has the same count as the pVal in the first branch. */
    Py_INCREF(pVal);  
} else {
    PyErr_SetString(PyExc_TypeError, "list items must be integer string literals or integers");
    return NULL;
}

或简单地依靠 PyInt_Type 来获得正确的结果。这不仅在 "single step" 中而且没有分支(检查 PyInt_CheckPyString_Check 是不必要的,因为这是在 int.__new__ 中完成的):

/* Convert pObj to an integer, this is equivalent to int(pObj) and works
   for integers and strings alike, however other inputs will fail. */
pVal = PyObject_CallFunctionObjArgs((PyObject *)&PyInt_Type, pObj, NULL);
if (pVal == NULL) {
    return NULL;
}