создание типа данных для переноса структур с помощью ctypes

#python #c #ctypes

#python #c #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 есть что-то подобное, я попытался обратиться к исходному коду, но я был перегружен. Есть ли имя для такого типа вещей или есть ссылка? Любое направление было бы действительно оценено.

Ответ №1:

Вот примерный пример того, как это можно было бы сделать. Все в 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]]
 

Комментарии:

1. Эй, спасибо за ваш ответ, я потратил большую часть дня на его переваривание, и это было действительно полезно. Это также помогло мне узнать больше о программировании на c 🙂