Python ctypes:通过示例,正确地将c_void_p子类用于传递和返回自定义数据类型

Python ctypes:通过示例,正确地将c_void_p子类用于传递和返回自定义数据类型,python,ctypes,Python,Ctypes,我正在使用ctypes,似乎不知道如何使用自定义数据类型。希望有一个Python接口,用于C++ Cys< /Cuff>类和C++ C++ > CyFiels类。p> 我当前的问题是使用C函数,名为 GETAYEnEntEngestAudioDIVE()/Cudio,下面定义了“代码>外”“C”{…/COD>。这个函数已被写入返回 Value*/Cudio>这是一个真正的 STD:vector < Cys*> ,指向C++的代码指针> Cys< /Cord>对象.< /P> 下面我的客户机代码显

我正在使用
ctypes
,似乎不知道如何使用自定义数据类型。希望有一个Python接口,用于C++<代码> Cys< /Cuff>类和C++ C++ > CyFiels类。p> <>我当前的问题是使用C函数,名为 GETAYEnEntEngestAudioDIVE()/Cudio,下面定义了“代码>外”“C”{…/COD>。这个函数已被写入返回<代码> Value*/Cudio>这是一个真正的<代码> STD:vector < Cys*> <代码>,指向C++的代码指针> Cys< /Cord>对象.< /P> 下面我的客户机代码显示了一个调用此函数的示例(通过Python
CellComplex
方法
elemen()
),在我看来它工作得很好。您会注意到我的
elemen()
的Python实现将返回类型
lib.elemen.restype
声明为(Python)的数组
Cell
对象。这就是我得到的,
>>print cmplx.elemen()
产生

[,,
, 
, 
]

但问题是:

现在,我想在列表中数组中的一个
单元格
对象上调用我的C函数。例如,
cmplx.elemen()[0][0]
是一个
,所以在我看来,我应该能够做到这一点:

cmplx.elemen()

我怀疑我没有正确地创建自定义Python类
Cell
CellComplex
。特别是在Python类
Cell
中,方法
dim(self):
我有一行
lib.dim.argtypes=[Cell]
,这肯定是完全伪造的。还有,我有一个愚蠢的Python类
c\u cellComplex
,它除了允许我自己指出某个特定的
ctypes.c\u void\u p
应该指向什么之外,什么都不做。事实上,我声称我对这些Python类的定义完全是伪造的,我被欺骗到墨迹我在正确的轨道上,奇迹般地运行了它(直到我尝试在假定的
Cell
实例上调用
Cell
方法为止)

客户端代码:

p = [[0,1],[0,1]] 
cmplx = cellComplex(p)
e = cmplx.elemen()

e[0][0].dim() # segfault
开始编辑提供了一个如何将c_void_p子类化的示例,并解决了一些其他概念问题-如果您有与我相同的问题,请从这里开始

segfault问题源于这样一个事实,即
extern C{…
中定义的
get_elementsAtSpecifiedDim()
将内存地址返回到
std::vector
,这是一种无法在Python中解析的数据类型。在这种情况下,我可以获取向量中的指针并返回它们,如下所示:

extern "C" {

  void * get_elementAtSpecifiedDimAndLoc(void *ptr, int dim, int nr) {
    cellComplex<double>* cmplx = static_cast<cellComplex<double>* >(ptr);
    cell<double>* c = cmplx->elemen()[dim][nr];
    return c;
  }
}
客户端代码现在可以工作。

结束编辑

这是一个伟大的愚蠢:

#cellComplex_python.py
lib=ctypes.cdll.LoadLibrary('./cellComplex_lib.so')
c类单元复合体(ctypes.c\u void\u p):
通过
类单元格(ctypes.c\u void\u p):
def dim(自身):
lib.dim.restype=ctypes.c_int
lib.dim.argtypes=[单元格]
self.dimension=lib.dim(self)
返回自我维度
类单元复合体(ctypes.c\u void\u p):
定义初始化(self,p):
自尺寸=透镜(p)
lib.new_cellComplex.restype=c_cellComplex
lib.new_cellComplex.argtypes=[(ctypes.c_double*2)*self.dimension,
ctypes.c\u size\u t]
e=[(ctypes.c_double*2)(p[i][0],p[i][1])表示范围内的i(自维)]
点=((ctypes.c_double*2)*自我维度)(*e)
self.cmplx=lib.new_单元复合体(点,self.dimension)
定义元素(自我):
lib.size\u elementsattspecifieddim.restype=ctypes.c\u int
lib.size_elementsattspecifieddim.argtypes=[c_cellComplex,
ctypes.c_int]
lib.get_elementsattspecifieddim.argtypes=[c_cellComplex,ctypes.c_int]
self.sizeAtDim=[]
self.elements=[]
对于范围内的i(自身尺寸+1):
self.sizeAtDim.append(lib.size\u elementsatsspecifieddim(self.cmplx,i))
lib.get_elementsattspecifieddim.restype=Cell*self.sizeAtDim[i]
self.elements.append(lib.get\u elementsatsspecifieddim(self.cmplx,i))
返回自我元素
C
code:

//cellComplex\u extern.cpp
#包括
#包括
外部“C”{
void*新单元复合体(双p[][2],尺寸尺寸){
std::vector点;
对于(size_t i=0;ielemen();
返回&e[dim];
}
int size_ELEMENTSATSPECIIEDDIM(无效*ptr,int dim){
cellComplex*cmplx=静态_铸造(ptr);
返回cmplx->elemen()[dim].size();
}  
内部尺寸(无效*ptr){
单元*ref=静态_铸造(ptr);
返回ref->dim();
}
}

<代码> > CyVoIDIp P< <代码>,您可以定义类方法<代码> FasyPARAM< /COD>和实例属性<代码> -AASTyrasePrime< /Cord>。如果您只代理一个C++属性对象,则可以不需要任何选项,如“代码”>Obj< <代码>。可以直接与ctypes指针、数组和结构一起使用,这在总体设计中可能很方便

以下示例可能会有所帮助:

from ctypes import *

__all__ = ['CellComplex']

class Cell(c_void_p):

    def __new__(cls, *args, **kwds):
        raise TypeError("cannot create %r instances" % cls.__name__)

    @property
    def dimension(self):
        return lib.dim(self)

class CellComplex(c_void_p):

    def __init__(self, p):
        pair = c_double * 2
        point = (pair * len(p))(*(pair(*q[:2]) for q in p))
        self.value = lib.new_cellComplex(point, len(p)).value

    @property
    def dimension(self):
        """Wrap a function that returns size_t."""
        return lib.????????(self)

    def get_elements(self):
        el = []
        for i in range(self.dimension):
            size = lib.size_elementsAtSpecifiedDim(self, i)
            cells = lib.get_elementsAtSpecifiedDim(self, i)
            el.append(cells[:size])
        return el
函数指针定义:

lib = CDLL('./cellComplex_lib.so')

lib.dim.restype = c_int
lib.dim.argtypes = [Cell]

lib.new_cellComplex.restype = CellComplex
lib.new_cellComplex.argtypes = [POINTER(c_double * 2), c_size_t]

lib.size_elementsAtSpecifiedDim.restype = c_int
lib.size_elementsAtSpecifiedDim.argtypes = [CellComplex, c_int]

lib.get_elementsAtSpecifiedDim.restype = POINTER(Cell)
lib.get_elementsAtSpecifiedDim.argtypes = [CellComplex, c_int]
我将函数指针定义从类方法定义中分离出来。无需每次调用方法时重新定义函数指针的
restype
argtypes
。如果函数返回大小可变的数组,最好将其设置为指针类型。可以将结果切片到列表或<代码>强制转换为数组类型

CellComplex
由浮点对的序列
p
初始化,如
[[0.1,0.2],[0.3,0.4],[0.5,0.6]

lib = CDLL('./cellComplex_lib.so')

lib.dim.restype = c_int
lib.dim.argtypes = [Cell]

lib.new_cellComplex.restype = CellComplex
lib.new_cellComplex.argtypes = [POINTER(c_double * 2), c_size_t]

lib.size_elementsAtSpecifiedDim.restype = c_int
lib.size_elementsAtSpecifiedDim.argtypes = [CellComplex, c_int]

lib.get_elementsAtSpecifiedDim.restype = POINTER(Cell)
lib.get_elementsAtSpecifiedDim.argtypes = [CellComplex, c_int]