Почему int (maxint) дает длинный, но int (int (maxint)) дает int? Это ошибка NumPy?

Довольно понятный (я на Windows):

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

Почему вызов int дает мне long, тогда как вызов его дважды дает мне int?

Является ли это ошибкой или функцией?

Ответы

Ответ 1

Этот вопрос специфичен для Numpy и Python 2. В Python 3 нет отдельных типов int и long.

Поведение происходит из-за ошибки "один за другим" в numpy. int(x) с одним аргументом преобразует x в число, вызывая PyNumber_Int(x). PyNumber_Int затем специально использует путь для подклассов int, поскольку 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 не передают условие, и вместо этого они преобразуются в PyLong в строка 1432:

return @[email protected](x);

с заменой @[email protected] на PyLong_FromLongLong в случае int_. Таким образом, возвращается long(sys.maxint).

Теперь, когда sys.maxint по-прежнему представляется int, int(long(sys.maxint)) возвращает int; аналогично int(sys.maxint + 1) возвращает a long.

Ответ 2

Как было предложено в другом (теперь удаленном) ответе, это кажется ошибкой из-за неправильного использования < вместо <=, но это не происходит из кода, приведенного в другом ответе. Этот код является частью логики печати, которая здесь не задействована.

Я считаю, что код, обрабатывающий вызовы int на скалярах NumPy, генерируется из в numpy/core/src/umath/scalarmath.c.src, соответствующая часть для подписанные целочисленные типы dtypes

    if(LONG_MIN < x && x < LONG_MAX)
        return PyInt_FromLong(x);
#endif
    return @[email protected](x);

Для целых чисел, строго связанных между LONG_MIN и LONG_MAX, этот код создает int. Для целого числа со значением LONG_MAX он возвращается к случаю return @[email protected](x);, где @[email protected] заменяется соответствующей функцией из семейства PyLongFrom* механизмом шаблона.

Таким образом, вызов int в NumPy int со значением LONG_MAX создает a long, но поскольку результат представляется как int, вызов int в результате снова создает int.