使用 ctypes 处理自定义数据类型

89 阅读2分钟

我在使用 ctypes 处理自定义数据类型时遇到了一些问题。我想为一个 C++ cell 类和一个 C++ cellComplex 类提供 Python 接口。我的当前问题是如何使用名为 get_elementAtSpecifiedDim() 的 C 函数,它返回一个 void ,实际上是一个 std::vector< cell >,一个指向 C++ cell 对象的指针向量。

我的 Python 代码中,我将 get_elementAtSpecifiedDim() 函数的返回类型声明为 (Python) Cell 对象的数组。例如,我调用 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>]。

huake_00066_.jpg 现在我想对我得到的Cell对象数组中的一个Cell对象调用我的C函数。但当我尝试这样做时,我遇到了段错误。我认为这是因为我没有正确地创建自定义的 Python 类 Cell 和 CellComplex。特别是在 Python 类 Cell 中,方法 dim(self): 将 lib.dim.argtypes 定义为 [Cell],这显然是错误的。

解决方案

为了解决这个问题,我需要正确地定义我的 Python 类 Cell 和 CellComplex。 我需要使用 ctypes.c_void_p 类来创建自定义的 Python 类 Cell 和 CellComplex,并使用正确的 restype 和 argtypes 来声明它们的函数和属性。

下面是修改后的代码:

# cellComplex_python.py
from ctypes import *

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

Function pointer definitions:
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]

这段代码使用 ctypes.c_void_p 类来创建自定义的 Python 类 Cell 和 CellComplex。它还使用正确的 restype 和 argtypes 来声明它们的函数和属性,以确保它们与底层的 C++ 代码兼容。

代码示例

p = [[0,1],[0,1]]
cmplx = cellComplex(p)
e = cmplx.get_elements()
print(e[0][0].dimension())

这段代码创建一个 CellComplex 对象,并调用它的 get_elements() 方法来获取 Cell 对象的数组。它然后打印出第一个 Cell 对象的维度。