cython中的函数更改numpy数组类型

时间:2019-07-02 09:29:10

标签: python numpy cython

我正在使用Cython和numpy,但是与更改numpy数组元素的dtype的cython函数有关的问题很奇怪。奇怪的是,仅在实际指定数组的输入类型时才更改dtype。

我在Ubuntu 18.04上使用Cython == 0.29.11,numpy == 1.15.4,python 3.6。

# cyth.pyx
cimport numpy as np

def test(x):
    print(type(x[0]))

def test_np(np.ndarray[np.uint32_t, ndim=1] x):
    print(type(x[0]))

现在将这个文件cythonize,并使用以下功能:

>>> from cyth import test, test_np
>>> import numpy as np
>>> a = np.array([1, 2], dtype=np.uint32)
>>> test(a)
<class 'numpy.uint32'>
>>> test_np(a)
<class 'int'>

因此test可以正常工作,打印输入数组中第一个元素的类型-uint32。但是实际上确保传入数组的类型为uint32的test_np现在将常规Python int作为第一个元素的类型。

即使试图强制元素为正确的类型也不起作用,即使用:

def test_np(np.ndarray[np.uint32_t, ndim=1] x):
    cdef np.uint32_t el
    el = x[0]
    print(type(el))

仍然导致

>>> test_np(a)
<class 'int'>

在理解这种差异方面的任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

Cython不会更改数组的类型,但是会返回类型稍有不同的元素。

numpy-array中的数据存储为32位无符号整数的连续字段。访问x[0]意味着创建一个Python对象(因为Python解释器无法处理原始C-ints)-numpy为每个numpy-dtype有一个专用的包装器类,并返回一个np.uint32对象。

Cython将所有简单的C整数类型(例如longint等)映射到Python整数(有意义)上。

现在,当导入numpy时,x[0]不再意味着使用numpy数组的__getitem__()(它将返回np.uint32对象),而是C整数(在这种情况下)无符号4字节),该值将转换为Python整数,因为“ return XXX”表示在def函数中表示结果必须是Python对象。

这确实意味着该数组具有不同的类型-当Cython将其转换为Python对象时,这些类型的映射会有所不同。


如果您希望将数据作为np.uint32对象访问,则可以调用__getitem__而不是[..]({[..]被Cython转换为对raw-C-的访问权限数据):

%%cython
cimport numpy as np

def test_np(np.ndarray[np.uint32_t, ndim=1] x):
    print(type(x[0]))                     # int
    print(type(x.__getitem__(0)))         # numpy.uint32

当您使用类型化的内存视图而不是ndarray时,直接调用__getitem__将返回内存视图的Python整数__getitem__而不是底层ndarray的__getitem__访问C级数据。调用基础对象的__getitem__进行内存查看:

def test_np(np.uint32_t[:] x):
    print(type(x[0]))
    print(type(x.base.__getitem__(0))) # instead of x.__getitem__(0)