Возврат из __len __(), когдa> 64 бит

В этой проблеме я занимаюсь сетевыми адресными пространствами IPv6, поэтому длина 2^(128-subnet).

Похоже, что python (по крайней мере, на этом компьютере) справится с 64-разрядным номером со знаком в качестве возвращаемого значения из __len__(). Поэтому len(IP('2001::/66')) работает, но len(IP('2001::/65')) не работает.

from IPy import IP
len(IP('2001::/64'))
Traceback (most recent call last):
  File "test.py", line 2, in <module>
      len(IP('2001::/64'))
OverflowError: long int too large to convert to int

Библиотека IPy находится под вопросом https://github.com/haypo/python-ipy.

Любые предложения о том, как с этим справиться, или намек на то, что это может быть ограничение, с которым я застрял?

Ответ 1

Проблема, с которой вы сталкиваетесь, заключается в том, что API Python C имеет системное ограничение на длину контейнеров. То есть функция C PyObject_Size возвращает значение Py_ssize_t, которое является подписанной версией стандартного типа C size_t. Его размер зависит от системы, но, возможно, 32-битные в 32-битных системах и 64-битные в 64-битных системах.

Встроенная функция len использует PyObject_Size, поэтому она имеет те же ограничения. Здесь его текущая реализация:

static PyObject *
builtin_len(PyObject *self, PyObject *v)
{
    Py_ssize_t res;

    res = PyObject_Size(v);
    if (res < 0 && PyErr_Occurred())
        return NULL;
    return PyInt_FromSsize_t(res);
}

Вы можете обойти это ограничение, используя метод len для объекта IP, вместо вызова встроенного len:

IP('2001::/64').len()

Это чистый питон, поэтому он не имеет ограничений на размер целого.