python - 无符号字符的 Cython 数组可以包含零吗?
问题描述
我想通过使用 Cython 来加速 Python 项目中的一些核心例程(我对两者都很陌生)。我正在编写带有相应 .py 类型信息的扩充 .pxd 文件。在一个 .py 中,我有一个类,其中有一个实例变量array.array
,我想成为 Cython 中的无符号字符数组。它可以编译,但我发现(经过艰苦的调试)每当在数组中的某处写入 0 时,它的长度就会发生变化,并且如果在 0 元素之外访问数组,则会引发 IndexError。
这是一个小(不确定它是最小的)示例。
内存.py:
import array
class Ram:
def __init__(self):
self.ram = array.array('B', [1,1,0,1,1])
print(len(self.ram))
内存.pxd:
cdef class Ram:
cdef unsigned char[5] ram
编译成扩展模块后得到的结果:
>>> import ram
>>> ram.Ram()
2
我尝试使用编译器指令关闭绑定检查,boundscheck = False
但无济于事。
如果我在 ram.pxd 中使用,它会按预期工作(长度为 5)cdef unsigned int[5] ram
,但我想使用字节数组。
如何保持数组的长度固定,同时仍然可以在其中写入 0?
(我正在使用 Cython 0.29.13 和 Python 3.7.4)
解决方案
您的问题在于len
数组而不是数组。len
是一个 Python 函数,因此不是为 char 数组“真正”定义的。然而,Cython 试图提供答案并默认使用strlen
计数方法,直到第一个 0 字节。在这种情况下,这是错误的,但这是一个明智的一般最佳猜测。
您可以定义这样的数组,并存储任何数据,包括0
. 你不能依赖 Cythonlen
来获取长度——在这种情况下,长度是一个常数,所以你知道它,但如果它是一个动态分配的数组,你将负责存储它。您可能还必须小心 Cython 的自动转换为 Python 字符串。
编辑:更多细节,因为我认为你并没有完全按照你的想法做:
cdef const char[5] ram
定义了一个长度为 5 的 C 数组。这是非常节省空间的(除了 5 个字符之外它不存储任何额外的数据),在 Cython 中可以快速访问,但没有 Python 等效项,因此在 Python 中访问它需要转换(自动,或者你自己做的事情)
ram = array.array(...)
将 Python 数组复制到 C 数组中。
我怀疑您应该改用memoryview:
cdef unsigned char[::1] ram # ::1 specifies C contiguous
这些空间效率稍低(它们存储一些 Python 引用计数信息和形状),并且在 Cython 中访问速度中等(您可以通过关闭边界检查和负索引以及指定 C 来使它们更快正如我在这里所做的那样)。更重要的是,它们可以在 Python 中访问(尽管以常规 Python 速度),并且 Cython 不会尝试将它们视为 C 字符串。
ram = array.array(...)
创建包含在数组中的数据的视图(无副本 - 它共享数据)。
推荐阅读
- ios - 使用泛型时无法调用 UIViewController 的非函数类型的值
- powershell - 移除导入的本地化数据
- eclipse - 有没有办法将智能插入添加到自定义 Eclipse 编辑器?
- reactjs - React Hooks - 改变孩子内部的状态不会反映在父母身上
- python - 使用堆栈溢出数据文件的熊猫数据帧
- html - 使用 flex-direction 列反向定位粘性
- amazon-mws - 销售伙伴 API 供稿 API
- multithreading - 为什么用Receiver声明receiver
? - dvc - 数据版本控制 (dvc) 无法推送到远程存储,因为查询缓存
- c++ - 为什么 shared_ptr 在函数中返回时没有隐式转换为布尔值?