Is there a an operation similar to PyInt_Check
/PyLong_Check
that takes into account whether or not the type has an __int__
method?
The closest workaround I have been able to find so far is
int check_int(PyObject *obj)
{
long lng;
int over;
lng = PyLong_AsLongAndOverflow(obj, &over);
if(lng == -1 && over == 0 && PyErr_Occurred()) {
PyErr_Clear();
#if PY_MAJOR_VERSION <= 2
lng = PyInt_AsLong(obj);
if(lng == -1L && PyErr_Occurred()) {
PyErr_Clear();
return 0;
}
#else
return 0;
#endif
}
return 1;
}
The problem here is that I am effectively doing something like
def isint(obj):
try:
int(obj)
except TypeError:
return False
else:
return True
However, this being C, I would prefer to do something like
def isint(obj):
return isinstance(obj, int) or hasattr(type(obj), '__int__')
I would expect such a check to already exist because PyInt_AsLong
and PyLong_AsLongAndOverflow
already perform it. I just want to be able to know if an object might be an integer without getting the integer value at all.
That being said, I can see the point of actually getting the value, since hasattr(type(obj), '__int__')
does not actually guarantee that the object can be reasonably used as an integer: e.g., if the attribute is not a function or just raises an error. In that case "no" may be a valid answer.
The closest thing to a function for that is PyNumber_Long
, or PyNumber_Int
on Python 2. Both of these functions actually perform the conversion. They will also consider methods like __trunc__
, and convert strings to ints, just like calling int
from Python-level code.
If you want to check for the presence of an __int__
conversion method, you can look for the corresponding slot directly:
if (o->ob_type->tp_as_number and o->ob_type->tp_as_number->nb_int) {
do_whatever();
}