gpt4 book ai didi

python - ctypes:例如,正确地子类化 c_void_p 以传递和返回自定义数据类型

转载 作者:太空宇宙 更新时间:2023-11-03 18:39:36 26 4
gpt4 key购买 nike

我正在与 ctypes 合作并且似乎无法弄清楚如何使用自定义数据类型。希望有一个 C++ 公共(public)方法的 Python 接口(interface) cell类和 C++ cellComplex类(class)。

我当前的问题是使用名为 get_elementsAtSpecifiedDim() 的 C 函数,在extern "C" {...下定义如下。该函数已编写为返回 void *确实std:vector< cell<double>* > ,指向 C++ 的指针向量 cell对象。

下面的我的客户端代码显示了调用此函数的示例(通过 Python CellComplex 方法 elemen() ),在我看来,这工作正常。您会注意到我的 elemen() 的 Python 实现声明返回类型 lib.elemen.restype成为 (Python) Cell 的数组对象。这就是我得到的,>>>print cmplx.elemen()产量

[<cellComplex_python.Cell_Array_8 object at 0x10d5f59e0>,
<cellComplex_python.Cell_Array_12 object at 0x10d5f5830>,
<cellComplex_python.Cell_Array_6 object at 0x10d5f58c0>,
<cellComplex_python.Cell_Array_1 object at 0x10d5f5950>]

但问题是:

现在我想在 Cell 之一上调用我的 C 函数此列表中的数组中的对象。例如,cmplx.elemen()[0][0]<Cell object at 0x10d5f5b00> ,所以在我看来我应该能够做到这一点:

cmplx.elemen()[0][0].dim()但这会出现段错误

我怀疑我没有创建自定义 Python 类 CellCellComplex正确。特别是在Python类中Cell ,方法dim(self):我有这条线 lib.dim.argtypes = [Cell] ,这绝对是假的。另外,我还有这个愚蠢的 Python 类 c_cellComplex除了让我向自己表明特定的 ctypes.c_void_p 之外,它什么也不做。应该是指。事实上,我声称我对这些 Python 类的定义完全是假的,并且我被这个奇迹般的运行所欺骗,认为我走在正确的轨道上(直到我尝试在一个对象上调用 Cell 方法)假设 Cell 实例...

客户端代码:

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

e[0][0].dim() # segfault

开始编辑 eryksun's answer below提供了如何子类化 c_void_p 的示例,并解决了一些其他概念性问题 - 如果您有与我相同的问题,请从这里开始。

段错误问题来自 get_elementsAtSpecifiedDim()定义于 extern C { ...将内存地址返回到 std::vector<cell<double>* > ,一种无法在 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;
}
}

可以这样调用:

def elemen(self):    
el = []
for i in range(self.dim):
size = lib.size_elementsAtSpecifiedDim(self,i)
cells = []
for j in range(size):
cells.append(lib.get_elementAtSpecifiedDimAndLoc(self,i,j))
el.append(cells)
return el
# put this somewhere
lib.get_elementAtSpecifiedDimAndLoc.restype = Cell
lib.get_elementAtSpecifiedDimAndLoc.argtypes = [CellComplex,c_int,c_int]

客户端代码现在可以运行。

结束编辑

这是一个巨大的愚蠢:

# cellComplex_python.py 
lib = ctypes.cdll.LoadLibrary('./cellComplex_lib.so')

class c_cellComplex(ctypes.c_void_p):
pass

class Cell(ctypes.c_void_p):

def dim(self):
lib.dim.restype = ctypes.c_int
lib.dim.argtypes = [Cell]
self.dimension = lib.dim(self)
return self.dimension

class CellComplex(ctypes.c_void_p):

def __init__(self,p):
self.dimension = len(p)
lib.new_cellComplex.restype = c_cellComplex
lib.new_cellComplex.argtypes = [(ctypes.c_double*2)*self.dimension,
ctypes.c_size_t]
e = [(ctypes.c_double*2)(p[i][0],p[i][1]) for i in range(self.dimension)]
point = ((ctypes.c_double*2)*self.dimension)(*e)
self.cmplx = lib.new_cellComplex(point,self.dimension)


def elemen(self):
lib.size_elementsAtSpecifiedDim.restype = ctypes.c_int
lib.size_elementsAtSpecifiedDim.argtypes = [c_cellComplex,
ctypes.c_int]
lib.get_elementsAtSpecifiedDim.argtypes = [c_cellComplex,ctypes.c_int]

self.sizeAtDim = []
self.elements = []
for i in range(self.dimension+1):

self.sizeAtDim.append(lib.size_elementsAtSpecifiedDim(self.cmplx,i))
lib.get_elementsAtSpecifiedDim.restype = Cell*self.sizeAtDim[i]
self.elements.append(lib.get_elementsAtSpecifiedDim(self.cmplx,i))

return self.elements

C代码:

// cellComplex_extern.cpp
#include<"cell.hpp">
#include<"cellComplex.hpp">

extern "C" {

void * new_cellComplex(double p[][2], size_t dim) {
std::vector< std::pair<double,double> > point;
for (size_t i=0; i<dim; ++i) {
point.push_back( std::make_pair(p[i][0],p[i][1]));
}
cellComplex<double>* cmplx = new cellComplex<double>(point);
return cmplx;
}

void * get_elementsAtSpecifiedDim(void *ptr, int dim) {
cellComplex<double>* cmplx = static_cast<cellComplex<double>* >(ptr);
std::vector<std::vector<cell<double>* > >* e = &cmplx->elemen();
return &e[dim];
}

int size_elementsAtSpecifiedDim(void *ptr, int dim) {
cellComplex<double>* cmplx = static_cast<cellComplex<double>* >(ptr);
return cmplx->elemen()[dim].size();
}

int dim(void *ptr) {
cell<double>* ref = static_cast<cell<double>* >(ptr);
return ref->dim();
}

}

最佳答案

您可以定义类方法 from_param 和实例属性 _as_parameter_,而不是子类化 c_void_p。如果您只是代理在私有(private)属性(例如 _obj)中引用的 C++ 对象,则可能不需要这两个选项。也就是说,c_void_p 的子类可以直接与 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]

我将函数指针定义与类方法定义分开。无需在每次调用方法时重新定义函数指针的 restypeargtypes。如果函数返回一个可变大小的数组,最好将其设置为指针类型。您可以将结果切片为列表或转换为数组类型。

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

我消除了 c_cellComplex 类。您只需设置实例的即可。

lib.new_cellComplex 返回 CellComplex 的实例,但当 时,ctypes 会绕过 __new____init__ CellComplex 用作 restype,因此这不是问题。重写 __new__ 会不会那么扭曲,但你仍然必须重写 c_void_p.__init__

dimension 属性需要是调用导出函数的属性,而不是依赖于 Python 对象中的静态数据。

关于python - ctypes:例如,正确地子类化 c_void_p 以传递和返回自定义数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20806070/

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