Python 为什么Cython期望0维?
我已将我的问题归结为一个小的可复制测试用例: 在文件1(custom_cython.pyx)文件中,我有以下内容:Python 为什么Cython期望0维?,python,numpy,cython,memoryview,Python,Numpy,Cython,Memoryview,我已将我的问题归结为一个小的可复制测试用例: 在文件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 f
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)
from custom_cython import lookup_memory
print(lookup_memory)
在文件2中(custom_cython_test.py),我有以下内容:
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)
from custom_cython import lookup_memory
print(lookup_memory)
当我运行python custom\u cython\u test.py
时,我得到了ValueError:Expected 0维,在lookup\u memory=np.zero(5000,dtype=input\u numpy\u dtype)行上得到了1
在我的结构定义中,我尝试在数据类型创建中使用cdef-packed-struct LOOKUPMEM\t
和align=False
,这会产生相同的错误
我使用的是Python 3.7.3,Cython版本为0.29.12,Numpy版本为1.16.4
我以前已经成功地将cython MemoryView分配给了1-D numpy数组,所以我很困惑,为什么我的1dcdef LOOKUPMEM\u t[:]lookup\u memory
需要0维。有谁能告诉我发生了什么事吗?问题似乎是结构的这一部分:
CELL_ID_t key_i
CELL_ID_t key_j
CELL_ID_t key_k
结合数据类型的这一部分:
("ijk", np.uint16, 3)
对于组合的offset\u和_num
字段也是如此
问题是,当memoryview接口看到一个类似元组的字段,如(“ijk”,np.uint16,3)
,它希望将其解压到一个由3个元素组成的一维数组中,但结构中的下一个键只是CELL\u ID\u t key\u i
,一个0-D标量
如果我将结构更改为与Numpy数据类型更紧密地匹配,它将起作用:
cdef struct LOOKUPMEM_t:
DTYPE_B_t filled_flag
CELL_ID_t ijk[3]
DTYPE_INT64_t offset_num_elements[2]
因此,对于如何继续,您有一些选择。如果确实希望保持结构的相同方式,可以这样做,并以不同的方式格式化数据类型。由于可以轻松查看具有不同数据类型的Numpy数组,因此如果您想在其他用例中保留现有的数据类型格式,您也可以使用不同的数据类型进行memoryview初始化。我可以使用Python 3.6.8和Cython 0.29.15进行复制。我还不知道问题出在哪里。谢谢你,至少我知道我没有疯!所讨论的错误似乎起源于Cython从一个相当复杂的函数生成的代码,该函数名为\uuuPyx\uValidateAndInit\uMemViewSlice
。我对Cython的类型化Memoryview区域并不十分熟悉,因此如果不仔细阅读代码,我仍然不清楚这意味着什么……有趣的是,如果将其更改为lookup\u memory=np.zeros(5000,dtype=input\u numpy\u dtype)。重塑(15000)
它将变成ValueError:Buffer的维度数错误(预期为1,得到2)
这是一个与前一个错误稍有不同的格式,奇怪?不奇怪;后一个错误是因为事实上将形状设置为(15000)会使其成为二维数组,因此需要声明cdef LOOKUPMEM\u t[:,:]lookup\u memory
,使其为二维。如果这样做,第一个错误仍然会发生。