我正在尝试使用以下命令通过 Cython 用 numpy
size_t
包装类型为 ndarray
的 C 指针数组:
cimport numpy as cnp
from libcpp.vector cimport vector
cnp.import_array()
cdef size_t num_layers = 10
cdef vector[size_t] steps_taken_vec = vector[size_t]()
steps_taken_vec.resize(3 * num_layers)
cdef size_t* steps_taken_ptr = steps_taken_vec.data()
cdef cnp.npy_intp[2] shape = [3, num_layers]
cdef cnp.npy_intp ndim = 2
self.shooting_method_steps_taken_array = cnp.PyArray_SimpleNewFromData(
ndim,
&shape[0],
cnp.NPY_UINTP, # <-- This is the problem
steps_taken_ptr) # steps_taken_ptr is a size_t*
上面会产生错误“cimported module has no attribute 'NPY_UINTP'”。根据 numpy 的文档,应该有一个枚举指示 numpy 使用 size_t 创建数组:https://numpy.org/devdocs/reference/c-api/dtype.html#c.NPY_TYPES.NPY_UINTP
PyArray_SimpleNewFromData
API 需要一个枚举来定义用于创建 ndarray 的类型。
但是,实际的 init.pxd 似乎没有该枚举。它确实正确设置了类型,请参见此处第 25 行,但此列表中没有枚举。
这些链接和我的代码使用的是 numpy 1.26.4。我展望了 2.0+,发现这种类型有一些定义上的变化,但枚举似乎仍然丢失(参见here)
作为一种解决方法,我使用
cnp.NPY_UINT64
,它可以工作,但我不确定它是否能保证跨平台和未来与 size_t
的大小相同。
我在这里遗漏了什么吗?
这是您在 Cython 中有效处理此问题的方法:
cnp.NPY_INTP
代替cnp.NPY_UINTP
。这映射到 npy_intp
,保证与平台上的 size_t
大小相同:your_module.pyx:
self.shooting_method_steps_taken_array = cnp.PyArray_SimpleNewFromData(
ndim,
&shape[0],
cnp.NPY_INTP,
steps_taken_ptr)
from libc.stdint cimport uint64_t, uint32_t
# Choose the appropriate type based on size_t
IF sizeof(size_t) == sizeof(uint64_t):
DEF SIZE_T_NPY_TYPE = cnp.NPY_UINT64
ELIF sizeof(size_t) == sizeof(uint32_t):
DEF SIZE_T_NPY_TYPE = cnp.NPY_UINT32
# Use it in your code
self.shooting_method_steps_taken_array = cnp.PyArray_SimpleNewFromData(
ndim,
&shape[0],
SIZE_T_NPY_TYPE,
steps_taken_ptr)
import numpy as np
dtype = np.dtype(np.uintp)
self.shooting_method_steps_taken_array = cnp.PyArray_SimpleNewFromData(
ndim,
&shape[0],
dtype.type_num,
steps_taken_ptr)
建议使用第一种方法
NPY_INTP
,因为它是最简单、最便携的解决方案。此类型专门设计用于匹配平台的指针大小,与 size_t
对齐。