Itertools не распознает numpy int как действительные входы на Python 3.6
Возьмите этот код:
import itertools as it
import numpy as np
data = ['a','b','c','d']
dw = np.array([1, 3], dtype=np.int64)
print(list(it.islice(data,dw[0],dw[1],1)))
В Python 2.7 он печатает ['b', 'c',]
, как ожидалось.
В Python 3.6 он генерирует исключение:
ValueError: Stop argument for islice() must be None or an integer: 0 <= x <= sys.maxsize.
То же самое относится к np.int32
, а другие методы пакета itertools
вызывают подобные ошибки, например. когда вы используете permutations
, вы получаете TypeError: Expected int as r
.
Я не мог найти многого, кроме этой проблемы с numpy и связанных с ней, но этот был закрыт 3 года назад, подразумевая, что это было решена.
И основные вещи, такие как индексирование с numpy ints data[dw[0]]
или логические сравнения, такие как dw[0] == 1
, работают очень хорошо.
Я что-то упустил? Может ли это быть ошибкой Python 3?
Ответы
Ответ 1
a numpy.int64
, по-видимому, не является подклассом int
a, b = dw[0], dw[1]
type(a)
numpy.int64
isinstance(a, int)
False
Документация по номеру
В документации упоминается это явно
Предупреждение
Тип int_ не наследуется от встроенного в Python 3, потому что тип int больше не является целым типом фиксированной ширины.
Решение
print(list(it.islice(data, int(dw[0]) , int(dw[1]), 1)))
или numpy slicing
data[dw[0]:dw[1]:1]
Ответ 2
Я не уверен, что это ошибка в Python 3 или нет, но похоже, что поведение изменилось с 2.7. В качестве проблемы с numpy, которую вы связали, описано в py27, либо numpy.int32
, либо numpy.int64
будет являться подклассом int
( в зависимости от того, используете ли вы 32- или 64-битную сборку Python); под py3 типы больше не связаны (numpy имеет числовые типы с фиксированной шириной, python int
- переменная ширина).
реализация itertools.islice
требует, чтобы его аргументы были объектами типа PyLong (который является именем API Python для типа Python int
). В частности, он вызывает PyLong_AsSize_t
, который преобразует объект Python в значение C size_t
. Этот метод, по-видимому, требует, чтобы его аргумент был фактически объектом Python int
, так как он вызывает PyLong_Check
. Я думаю, что этот метод в целом эквивалентен Python isinstance(obj, int)
, что объясняет разницу в поведении между py2 и py3 здесь.
Индексирование нормального списка использует другой более толерантный метод для приведения аргументов в положительные целочисленные значения, называемые PyNumber_AsSsize_t
.
Это проверяет, является ли его аргумент int
и, если нет, возвращается к попытке вызвать его аргумент __index__
method; как указывает @MarkDickinson, числовые типы numpy реализуют этот метод, поэтому все работает нормально. Возможно, это было бы более интуитивно понятным для itertools.islice
.
Ответ 3
Это похоже на случай магического метода __index__
(который уже реализует целые числа numpy). Я предлагаю поднимать проблему на трекер, запрашивая это как усовершенствование, - что islice принимает любой объект, который реализует __index__
.
Ответ 4
Если вы хотите сохранить объект islice
/slice
-like, используйте np.s_
:
slice = np.s_[dw[0]: dw[1]: 1]
data[slice]
['b', 'c']
поскольку np.s_
является объектом numpy
, он не имеет против целых чисел numpy
.