itertools不会将numpy int识别为Python 3.6上的有效输入

Khr*_*ris 14 python numpy python-itertools python-3.x

拿这个代码:

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)))
Run Code Online (Sandbox Code Playgroud)

在Python 2.7上,它['b', 'c',]按预期打印.

在Python 3.6上它抛出一个异常:

ValueError: Stop argument for islice() must be None or an integer: 0 <= x <= sys.maxsize.
Run Code Online (Sandbox Code Playgroud)

同样的np.int32方法,并且itertools包的其他方法抛出类似的错误,例如当你使用permutations时得到TypeError: Expected int as r.

除了这个numpy问题和相关问题之外,我找不到太多关于此 问题,但是那个问题在3年前被关闭,暗示它已经解决了.

基本的东西,比如使用numpy int进行索引data[dw[0]]或布尔比较dw[0] == 1就好了.

我错过了什么吗?这可能是Python 3的错误吗?

Maa*_*bré 14

a numpy.int64显然不是.的子类int

a, b = dw[0], dw[1]
Run Code Online (Sandbox Code Playgroud)

type(a)

numpy.int64
Run Code Online (Sandbox Code Playgroud)

isinstance(a, int)

False
Run Code Online (Sandbox Code Playgroud)

Numpy文档

文件提到了这一点明确

警告

int_type不从Python 3中的int内置继承,因为int类型不再是固定宽度的整数类型.

print(list(it.islice(data, int(dw[0]) , int(dw[1]), 1)))
Run Code Online (Sandbox Code Playgroud)

或numpy切片

data[dw[0]:dw[1]:1]
Run Code Online (Sandbox Code Playgroud)

  • @Chris_Rands:常规列表切片和索引支持任何实现`__index__`方法的东西.NumPy整数类型实现该方法. (4认同)
  • @MarkDickinson好的,已经提出了一个bug问题(不是我)http://bugs.python.org/issue30537 (4认同)
  • @MarkDickinson谢谢; 那个设计有原因吗?为什么不让`islice`支持`__index__`方法呢?虽然也许没有真正的需要,因为投射到"int"是多么容易...... (2认同)

wil*_*elm 6

我不确定它是否是Python 3中的错误,但看起来自2.7以来行为发生了变化.正如你所链接的那个numpy问题所描述的那样,在py27下,要么是numpy.int32或者numpy.int64看起来是一个子类int(取决于你是否使用32位或64位的Python构建); 在py3下,类型不再相关(numpy有固定宽度的数字类型,python int是可变宽度).

实施itertools.islice需要它的参数是类型PyLong(对象是Python的API名称为Python的int类型).具体来说,它调用PyLong_AsSize_t,将Python对象转换为C size_t值.这个方法似乎要求它的参数实际上是一个Python int对象,因为它调用PyLong_Check.我认为这种方法大致相当于Python isinstance(obj, int),它解释了py2和py3之间行为的差异.

正常列表索引使用另一个更宽容的方法将参数强制转换为正整数值,称为PyNumber_AsSsize_t.这将检查它的参数是否为a int,如果不是,则返回尝试调用其参数的__index__方法; 正如@MarkDickinson指出的那样,numpy的数值类型实现了这个方法,所以一切正常.也许这将是一个更直观的事情itertools.islice.