我有一个函数,我想使用Cython,涉及处理大量固定长度的字符串 . 对于标准的cython函数,我可以声明类似的数组:
cpdef double[:] g(double[:] in_arr):
cdef double[:] out_arr = np.zeros(in_arr.shape, dtype='float64')
cdef i
for i in range(len(in_arr)):
out_arr[i] = in_arr[i]
return out_arr
当dtype是像 int32
, float
, double
等简单的东西时,这会编译并按预期工作 . 但是,我无法弄清楚如何创建固定长度字符串的类型化存储器视图 - 例如,相当于 np.dtype('a5')
.
如果我用这个:
cpdef str[:] f(str[:] in_arr):
# arr should be a numpy array of 5-character strings
cdef str[:] out_arr = np.zeros(in_arr.shape, dtype='a5')
cdef i
for i in range(len(in_arr)):
out_arr[i] = in_arr[i]
return out_arr
该函数编译,但这:
in_arr = np.array(['12345', '67890', '22343'], dtype='a5')
f(in_arr)
引发以下错误:
---> 16 cpdef str [:] f(str [:] in_arr):17#arr应该是一个5字符串的numpy数组18 cdef str [:] out_arr = np.zeros(in_arr.shape,dtype ='a5')ValueError:缓冲区dtype不匹配,预期'unicode对象'但得到一个字符串
类似地,如果我使用 bytes[:]
,它会给出错误"Buffer dtype mismatch, expected 'bytes object' but got a string" - 这甚至不会导致问题,因为我没有指定这些字符串的长度为6 .
有趣的是,我可以在结构化类型中包含固定长度的字符串,如this question,但我没有't think that'是声明类型的正确方法 .
1 回答
在Python3会话中,
a5
数组包含字节串 .http://cython.readthedocs.io/en/latest/src/tutorial/strings.html表示
str
在使用Python3编译时是unicode字符串类型 .我怀疑
np.array(['12345', '67890', '22343'], dtype='U5')
将被接受为您的函数的输入数组 . 但是复制到a5
out_arr
会有问题 .对象版本
此循环的对象版本有效:
这些函数返回一个内存视图,必须将其转换为要打印的数组 .
单个char版本
单字节memoryview复制:
使用
view
将字符串转换为单个字节并返回 .2 d unicode版本
我去年调查过这个问题:Cython: storing unicode in numpy array
这会处理unicode字符串,就像它们是2d int数组的行一样;之前和之后需要重塑 .
对于字节串,类似的2d
char
版本应该可以工作 .c struct version
C结构正在创建一个包含5个字节元素的内存视图,这些元素映射到数组
S5
元素 .https://github.com/cython/cython/blob/master/tests/memoryview/numpy_memoryview.pyx也有一个带字节串的结构化数组示例 .