为什么 Cython 期望 0 维?
Why does Cython expect 0 dimensions?
我已将我的问题归结为一个可重现的小测试用例:
在文件 1 (custom_cython.pyx) 中我有以下内容:
import numpy as np
cimport numpy as np
cimport cython
ctypedef np.uint8_t DTYPE_B_t
ctypedef np.uint16_t CELL_ID_t
ctypedef np.int64_t DTYPE_INT64_t
cdef struct LOOKUPMEM_t:
DTYPE_B_t filled_flag
CELL_ID_t key_i
CELL_ID_t key_j
CELL_ID_t key_k
DTYPE_INT64_t offset
DTYPE_INT64_t num_elements
cdef LOOKUPMEM_t[:] lookup_memory
my_dtype = [("filled_flag", np.uint8, 1),
("ijk", np.uint16, 3),
("offset_and_num", np.int64, 2)]
input_numpy_dtype = np.dtype(my_dtype, align=True)
lookup_memory = np.zeros(5000, dtype=input_numpy_dtype)
在文件 2 (custom_cython_test.py) 中,我有以下内容:
from custom_cython import lookup_memory
print(lookup_memory)
当我 运行 python custom_cython_test.py
我最终在 lookup_memory = np.zeros(5000, dtype=input_numpy_dtype)
行上得到 ValueError: Expected 0 dimension(s), got 1
在我的结构定义中,我尝试在 dtype 创建中使用 cdef packed struct LOOKUPMEM_t
和 align=False
,这会产生相同的错误。
我正在使用 Python 3.7.3,Cython 版本 0.29.12 和 Numpy 1.16.4。
我之前已经成功地将 cython memoryviews 分配给一维 numpy 数组,所以我很困惑为什么我明显的 1d cdef LOOKUPMEM_t[:] lookup_memory
期望 0 维。谁能告诉我这是怎么回事?
问题似乎出在你的结构的这一部分:
CELL_ID_t key_i
CELL_ID_t key_j
CELL_ID_t key_k
结合你的数据类型的这一部分:
("ijk", np.uint16, 3)
对于您的组合 offset_and_num
字段也是如此。
问题是,当 memoryview 接口看到像 ("ijk", np.uint16, 3)
这样的类似元组的字段时,它想将其解压缩为 3 个元素的一维数组,但结构中的下一个键只是 CELL_ID_t key_i
,一个 0-D 标量。
如果我更改您的结构以更接近地匹配 Numpy dtype 它会起作用:
cdef struct LOOKUPMEM_t:
DTYPE_B_t filled_flag
CELL_ID_t ijk[3]
DTYPE_INT64_t offset_num_elements[2]
所以你有几个选择如何继续。如果你真的想保持你的结构不变,你可以这样做,并以不同的方式格式化数据类型。由于很容易查看具有不同 dtype 的 Numpy 数组,如果您想为其他用例保留现有的 dtype 格式,您也可以使用不同的 dtype 进行内存视图初始化。
我已将我的问题归结为一个可重现的小测试用例:
在文件 1 (custom_cython.pyx) 中我有以下内容:
import numpy as np
cimport numpy as np
cimport cython
ctypedef np.uint8_t DTYPE_B_t
ctypedef np.uint16_t CELL_ID_t
ctypedef np.int64_t DTYPE_INT64_t
cdef struct LOOKUPMEM_t:
DTYPE_B_t filled_flag
CELL_ID_t key_i
CELL_ID_t key_j
CELL_ID_t key_k
DTYPE_INT64_t offset
DTYPE_INT64_t num_elements
cdef LOOKUPMEM_t[:] lookup_memory
my_dtype = [("filled_flag", np.uint8, 1),
("ijk", np.uint16, 3),
("offset_and_num", np.int64, 2)]
input_numpy_dtype = np.dtype(my_dtype, align=True)
lookup_memory = np.zeros(5000, dtype=input_numpy_dtype)
在文件 2 (custom_cython_test.py) 中,我有以下内容:
from custom_cython import lookup_memory
print(lookup_memory)
当我 运行 python custom_cython_test.py
我最终在 lookup_memory = np.zeros(5000, dtype=input_numpy_dtype)
ValueError: Expected 0 dimension(s), got 1
在我的结构定义中,我尝试在 dtype 创建中使用 cdef packed struct LOOKUPMEM_t
和 align=False
,这会产生相同的错误。
我正在使用 Python 3.7.3,Cython 版本 0.29.12 和 Numpy 1.16.4。
我之前已经成功地将 cython memoryviews 分配给一维 numpy 数组,所以我很困惑为什么我明显的 1d cdef LOOKUPMEM_t[:] lookup_memory
期望 0 维。谁能告诉我这是怎么回事?
问题似乎出在你的结构的这一部分:
CELL_ID_t key_i
CELL_ID_t key_j
CELL_ID_t key_k
结合你的数据类型的这一部分:
("ijk", np.uint16, 3)
对于您的组合 offset_and_num
字段也是如此。
问题是,当 memoryview 接口看到像 ("ijk", np.uint16, 3)
这样的类似元组的字段时,它想将其解压缩为 3 个元素的一维数组,但结构中的下一个键只是 CELL_ID_t key_i
,一个 0-D 标量。
如果我更改您的结构以更接近地匹配 Numpy dtype 它会起作用:
cdef struct LOOKUPMEM_t:
DTYPE_B_t filled_flag
CELL_ID_t ijk[3]
DTYPE_INT64_t offset_num_elements[2]
所以你有几个选择如何继续。如果你真的想保持你的结构不变,你可以这样做,并以不同的方式格式化数据类型。由于很容易查看具有不同 dtype 的 Numpy 数组,如果您想为其他用例保留现有的 dtype 格式,您也可以使用不同的 dtype 进行内存视图初始化。