Python 无符号字符的Cython数组是否可以包含零?

Python 无符号字符的Cython数组是否可以包含零?,python,cython,Python,Cython,我想通过使用Cython来加速Python项目中的一些核心例程(我对两者都很陌生)。我正在为相应的.py编写带有类型信息的扩充.pxd文件。在one.py中,我有一个类,带有一个实例变量array.array,我希望它是Cython中的无符号字符数组。 它可以编译,但我发现(经过艰苦的调试后)每当在数组中的某个位置写入0时,其长度都会发生变化,如果访问数组时超出了0元素,则会引发索引器 下面是一个小的(不确定它是否最小)示例 ram.py: import array class Ram: d

我想通过使用Cython来加速Python项目中的一些核心例程(我对两者都很陌生)。我正在为相应的.py编写带有类型信息的扩充.pxd文件。在one.py中,我有一个类,带有一个实例变量
array.array
,我希望它是Cython中的无符号字符数组。 它可以编译,但我发现(经过艰苦的调试后)每当在数组中的某个位置写入0时,其长度都会发生变化,如果访问数组时超出了0元素,则会引发索引器

下面是一个小的(不确定它是否最小)示例

ram.py:

import array

class Ram:

def __init__(self):
    self.ram = array.array('B', [1,1,0,1,1])
    print(len(self.ram))
ram.pxd:

cdef class Ram:
    cdef unsigned char[5] ram
编译成扩展模块后得到的结果:

>>> import ram
>>> ram.Ram()
2
我尝试用编译器指令
boundscheck=False
关闭绑定检查,但没有成功

如果我在ram.pxd中使用
cdef unsigned int[5]ram
,它会按预期工作(长度为5),但我希望使用字节数组

如何保持数组的长度不变,同时仍能在其中写入0


(我正在使用Cython 0.29.13和Python 3.7.4)

您的问题在于
len
而不是数组
len
是一个Python函数,因此不是为字符数组“真正”定义的。然而,Cython试图提供一个答案,并默认使用
strlen
方法进行计数,直到第一个0字节。在这种情况下,这是错误的,但这是一个合理的一般最佳猜测

您可以这样定义一个数组,并存储任何数据,包括
0
。你不能依赖Cython的
len
来获取长度——在这种情况下,长度是一个常数,所以你知道它,但是如果它是一个动态分配的数组,你就要负责存储它。您可能还必须小心Cython自动转换为Python字符串


编辑:再详细一点,因为我不认为你在做你认为的事情:

cdef const char[5] ram
定义长度为5的C数组。这非常节省空间(除了5个字符外,它不存储额外的数据),在Cython中可以快速访问,但没有与Python等效的内容,因此在Python中访问它需要转换(自动或您自己做的事情)

将Python数组复制到C数组中

我怀疑您应该使用memoryview:

cdef unsigned char[::1] ram # ::1 specifies C contiguous
它们的空间效率稍低(它们存储一些Python引用计数信息和一个形状),并且在Cython中访问速度适中(可以通过关闭边界检查和负索引,以及像我在这里所做的那样指定C continuous来加快访问速度)。更重要的是,可以用Python访问它们(尽管是以常规Python速度),Cython不会试图将它们当作C字符串

ram = array.array(...)

创建数组中包含的数据的视图(无副本-它共享数据)。

Thank you@DavidW,这很有帮助。我认为我的问题是双重的。一方面是Python的
len
,我现在明白了。另一方面可能与您提到的自动转换为Python字符串有关。如果我在.pxd文件的
ram
声明中使用
public
,然后从Python访问
ram().ram[3]
,我会得到一个
索引器:索引超出范围
。这是因为转换为以null结尾的字符串吗?@user3725511-是的,我认为
cdef public
属性只是将其转换为以null结尾的字符串。我在编辑中编辑了更多的细节——重读了你的问题后,我认为你没有完全按照你的想法去做,你可能会发现记忆视图是一种更好的方法
ram = array.array(...)