为什么int(maxint)给出一个long,但int(int(maxint))给出一个int?这是一个NumPy错误吗?

时间:2017-05-24 10:19:50

标签: python python-2.7 numpy int long-integer

相当不言自明(我在Windows上):

>>> import sys, numpy
>>> a = numpy.int_(sys.maxint)
>>> int(a).__class__
<type 'long'>
>>> int(int(a)).__class__
<type 'int'>

为什么调用int一次给我一个long,而调用它两次会给我一个int

这是一个错误还是一个功能?

2 个答案:

答案 0 :(得分:4)

正如(现已删除)其他答案中所提出的,由于<而不是<=的使用不正确,这似乎是一个错误,但它并非来自在另一个答案中引用的代码。该代码是打印逻辑的一部分,这里不涉及。

我相信处理NumPy标量的int调用的代码是从numpy/core/src/umath/scalarmath.c.src中的template生成的,有条件的整数dtypes的相关部分是

    if(LONG_MIN < x && x < LONG_MAX)
        return PyInt_FromLong(x);
#endif
    return @func@(x);

对于严格在LONG_MINLONG_MAX之间的整数,此代码会生成int。对于值为LONG_MAX的整数,它会回退到return @func@(x);大小写,其中@func@由模板引擎从PyLongFrom*系列中的适当函数替换。

因此,在值为int的NumPy int上调用LONG_MAX会生成long,但由于结果可以表示为int,因此再次调用结果int产生int

答案 1 :(得分:4)

这个问题特定于Numpy和Python 2.在Python 3中,没有单独的intlong类型。

由于numpy中的off-by-one错误导致行为发生。带有一个参数的int(x)会通过调用PyNumber_Int(x)x转换为数字。 PyNumber_Int然后专门接受path for int subclasses,因为int64返回的numpy.int_int的子类:

m = o->ob_type->tp_as_number;
if (m && m->nb_int) { /* This should include subclasses of int */
    /* Classic classes always take this branch. */
    PyObject *res = m->nb_int(o);
    if (res && (!PyInt_Check(res) && !PyLong_Check(res))) {
        PyErr_Format(PyExc_TypeError,
                     "__int__ returned non-int (type %.200s)",
                     res->ob_type->tp_name);
        Py_DECREF(res);
        return NULL;
    }
    return res;
}

现在,对于此代码调用a->ob_type->tp_as_number->nb_int,它在numpy/core/src/umath/scalarmath.c.src中实现。这是针对不同类型进行参数化的代码的位置;这个用于<typename>_int方法的方法,用于填充nb_int方法广告位。它有以下一个if

if(LONG_MIN < x && x < LONG_MAX)
    return PyInt_FromLong(x);

两个运营商都应该<=。在<处,LONG_MINLONG_MAX都没有通过条件,而是在line 1432转换为PyLong

return @func@(x);
@func@的情况下,PyLong_FromLongLongint_替换为long(sys.maxint)。因此,返回sys.maxint

现在,由于int仍可由int(long(sys.maxint))表示,int会返回int(sys.maxint + 1);同样long会返回{{1}}。