首页 > 解决方案 > 使用 ctypes 创建用于包装结构的数据类型

问题描述

所以我正在学习ctypes,我有类似以下的情况:

我有一个共享库,其中包含实现双精度矩阵和复数矩阵的结构。我想用ctypes. 我知道我可以创建两个类来包装每个结构,但我想知道是否有一种直接的方法可以通过指定数据类型将两个结构与一个类一起包装。

例如,也许我的库libmatrix.so有以下源文件:

// matrix.c

struct complex {
    double re;
    double im;
};

struct Matrix {
    int nrow;
    int ncol;
    double *data
};

struct CMatrix {
    int nrow;
    int ncol;
    complex *data
};

typedef struct complex complex;
typedef struct Matrix Matrix;
typedef struct CMatrix CMatrix;

包装我的complex结构后,可能是这样的:

class complex(Structure):
    __fields__ = [("re", c_double), ("im", c_double)]

在 python 中,我想创建一个Matrix让我执行以下操作的类:

# create 2 x 3 matrix of doubles 
m = Matrix(2, 3, dtype=c_double)

# create 2 x 3 matrix of complex numbers (structure that I made)
n = Matrix(2, 3, dtype=complex)

我知道 numpy 有这样的东西,我尝试查阅源代码,但我不知所措。这种类型的东西有名称或有参考吗?任何方向将不胜感激。

标签: pythoncctypes

解决方案


这是一个粗略的例子,它是如何完成的。Python 中的一切都是对象,因此可以直接传递数据类型并用于分配数组。一些覆盖使矩阵更易于操作和显示。

from ctypes import *
from pprint import pformat

class Complex(Structure):

    _fields_ = (('re',c_double),
                ('im',c_double))

    def __repr__(self):
        return f'Complex({self.re}{self.im:+}j)'

    def __str__(self):
        return f'{self.re}{self.im:+}j'

class Matrix(Structure):

    _fields_ = (('nrow',c_int),
                ('ncol',c_int),
                ('data',c_void_p))

    def __init__(self,row,col,dtype):
        self.nrow = row
        self.ncol = col
        self._data = (dtype * col * row)() # internal instance of allocated array
        self.data = cast(byref(self._data),c_void_p) # generic pointer to array

    # forward to the array instance
    def __getitem__(self,key):
        return self._data.__getitem__(key)

    # forward to the array instance
    def __setitem__(self,key,value):
        return self._data.__setitem__(key,value)

    def __repr__(self):
        return pformat([r[:] for r in self._data])

mc = Matrix(2,3,Complex)
md = Matrix(3,2,c_double)
mc[1][2] = Complex(1.1,-2.2)
md[2][1] = 1.5
print(mc)
print(md)

输出:

[[Complex(0.0+0.0j), Complex(0.0+0.0j), Complex(0.0+0.0j)],
 [Complex(0.0+0.0j), Complex(0.0+0.0j), Complex(1.1-2.2j)]]
[[0.0, 0.0], [0.0, 0.0], [0.0, 1.5]]

推荐阅读