相当不言自明(我在Windows上):
>>> import sys, numpy
>>> a = numpy.int_(sys.maxint)
>>> int(a).__class__
<type 'long'>
>>> int(int(a)).__class__
<type 'int'>
为什么调用int
一次给我一个long
,而调用它两次会给我一个int
?
这是一个错误还是一个功能?
答案 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_MIN
和LONG_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中,没有单独的int
和long
类型。
由于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_MIN
和LONG_MAX
都没有通过条件,而是在line 1432转换为PyLong
:
return @func@(x);
在@func@
的情况下,PyLong_FromLongLong
被int_
替换为long(sys.maxint)
。因此,返回sys.maxint
。
现在,由于int
仍可由int(long(sys.maxint))
表示,int
会返回int(sys.maxint + 1)
;同样long
会返回{{1}}。