With CPython 2.7, can a PyStringObject
object be converted directly to a PyIntObject
?
Currently, I convert a Python string into a Python integer using two functions, 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;
}
This works fine, but I was wondering if the conversion is possible in a single step?
Actually you can simply call PyInt_Type
with PyObject_CallFunctionObjArgs
:
pVal = PyObject_CallFunctionObjArgs((PyObject *)&PyInt_Type, pObj, NULL);
However you need to check the returned pVal
for NULL
. You said "This works fine" but what if you use something like "a"
(Python String not C char!) as pObj
? My guess this will segfault when you call PyObject_Print
.
Generally you need to check all return values if there is the slightest chance something might go wrong. Otherwise you might run into all sorts of trouble, for example when you pass in NULL
into some other function (segmentation fault) or return a value when an exception is set (SystemError). Also your reference counts depending on the branch are different. You might handle that later in the code but in general you could just increment the reference count in the second branch so you don't need additional if
s later on. So I would suggest using:
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;
}
or simply rely on PyInt_Type
to get it right. This is not only in a "single step" but also without branches (checking for PyInt_Check
or PyString_Check
is unnecessary because that's done in 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;
}