gpt4 book ai didi

python - 如何从Python访问具有固定大小数组的C结构内部数据?

转载 作者:行者123 更新时间:2023-12-01 01:25:33 24 4
gpt4 key购买 nike

我知道这是重复的 Writing Cython extension: how to access a C struct internal data from Python?

但是我还没有找到任何资源来处理这样的 C 结构,

ctypedef struct IoRegAccess:        
int Addr[26]
int Data[26]
int AddrLen
int DataLen

使用__getitem__/__setitem__方法我们可以访问这个结构数组,但我有兴趣在特定类中使用@property来实现它

  cdef class PyIoRegAccess:
cdef IoRegAccess RegContainer

#ctor of this class
def __cinit__(self):
memset(self.RegContainer.uiAddr, 0,sizeof(uint32_t)*26)
memset(self.RegContainer.uiData, 0,sizeof(uint32_t)*26)


@property
def uiAddr(self,key):
return self.RegContainer.uiAddr[key]

@uiAddr.setter
def uiAddr(self, key, value):
self.RegContainer.uiAddr[key] = value

现在我有两个错误,

特殊方法 __get__ 的参数数量错误(声明 2 个,预期 1 个)

特殊方法__set__的参数数量错误(声明了3个,预期有2个)

请对此提出建议

最佳答案

看来您正在尝试以不符合预期的方式使用属性(property)。可以在您的场景中使用属性,但从性能的角度来看,这可能并不明智,因为这个答案将在下面进一步显示。

在纯 Python 中,您可以使用(您肯定已经知道)属性,如下所示来访问列表中的元素:

def class A:
def __init__(self):
self._lst=[1,2,3,4]
@property
def lst(self):
return self._lst

即属性不用于访问列表的元素,而是用于访问列表本身。

现在

a=A()
a.lst # accesses list via property
a.lst[0] = 10 # accesses list via property + __getitem__ of the list
# no property-setter needed, we don't set lst-property,
# just an element of the list

a.lst[0] # returns 10

将相同的想法天真地翻译成 Cython 将是(您的示例有些简化):

%%cython
from libc.string cimport memset

cdef class CyA:
cdef int _Addr[26]

def __cinit__(self):
memset(self._Addr, 0,sizeof(int)*26)

@property
def Addr(self):
return self._Addr

但是,这并不像人们想象的那样有效:

a=CyA()
a.Addr[0] = 10

a.Addr[0] # returns 0!

问题是,Cython 在幕后将 int C 数组转换为列表(这是多么大的开销!)并更改 Addr 数组的副本根本不改变原始数组。

您需要在属性中返回数组_Addr的(类型化)内存 View :

%%cython
....
@property
def Addr(self):
cdef int[:] memview = self._Addr
return memview

按预期工作:

a=CyA()
a.Addr[0] = 10

a.Addr[0] # returns 10, as expected!

您可能会担心仅为一次访问创建内存 View 的开销(您是对的),在这种情况下,可以缓存创建的内存 View 并一遍又一遍地重用它:

%%cython

cdef class CyA:
cdef int _Addr[26]
cdef int[:] memview_cache
def __cinit__(self):
memset(self._Addr, 1204,sizeof(int)*26)
self.memview_cache = None

...
@property
def Addr_fast(self):
if self.memview_cache is None:
self.memview_cache = self._Addr
return self.memview_cache

导致速度提高3:

a=CyA()
%timeit a.Addr # 1.05 µs ± 36.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit a.Addr_fast # 328 ns ± 13.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

然而,与通过 __setitem__ 进行简单且直接的元素设置相比,这仍然是太多的开销:

%%cython
cdef class CyA:
cdef int _Addr[26]
...
def __setitem__(self, index, int value):
self._Addr[index] = value

这会导致

a=CyA()
%timeit a.Addr_fast[0] = 10 # 483 ns ± 22.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit a[0] = 10 # 32.5 ns ± 0.669 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

大约快了 10 倍!

关于python - 如何从Python访问具有固定大小数组的C结构内部数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53387105/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com