3

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.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264

1 Answers1

1

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();
}
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • As I noted in the end of my question, I am perfectly fine to do the conversion, I just didn't want to do it myself. It is also very nice that both functions eat up the exception. I will still have to add the `#if`, but that is a small price to pay. – Mad Physicist Mar 29 '18 at 18:33
  • Thanks for the update. Perhaps that is not what I want after all. Excellent answer and food for thought. – Mad Physicist Mar 29 '18 at 18:37
  • @MadPhysicist: I'm not sure about the exception part; the docs don't mention raising an exception, but the [implementation](https://github.com/python/cpython/blob/v3.6.4/Objects/abstract.c#L1314) seems to produce an exception for invalid input. – user2357112 Mar 29 '18 at 18:38
  • That is to be expected since `int` raises a `TypeError` if you try funny stuff. – Mad Physicist Mar 29 '18 at 18:45