Подкласс ctypes.c_void_p для представления пользовательского обработчика с пользовательской функцией C для конструктора Python

Программы на Python
Anonymous
Подкласс ctypes.c_void_p для представления пользовательского обработчика с пользовательской функцией C для конструктора

Сообщение Anonymous »

У меня несколько экзотический вопрос.
Представьте, что есть какой-то интерфейс C с такими операциями (на практике я имею в виду webrtc vad API):

Код: Выделить всё

Handler* create();
int process(Handler*);
void free(Handler*);
Я знаю, как представить эти функции с помощью ctypes и ctypes.c_void_p для представления указателя на обработчик.
Теперь экзотический вопрос. Можно ли представить этот шаблон как класс, производный от ctypes.c_void_p?
  • В целом правильно ли производить производный от ctypes.c_void_p?
  • Есть ли какие-либо ограничения для конструктора такого производного класса? Будет ли конструктор использоваться ctypes для создания маршаллированных возвращаемых дескрипторов?
  • Правильно ли изменять self.value в производном классе __init__?
  • Как ctypes создает объект HandlerPointer, будет ли он вызывать __init__ и будет ли это препятствовать его правильному функционированию?
  • Вызывает ли ctypes правильно поддерживать/маршалировать c_void_p-argtypes/restypes, производные от c_void_p?
  • Есть ли более естественный способ представления таких капсулоподобных объектов (указатель на возможно непрозрачную структуру вместе с деструктором функция)/API?
Например. сделать что-то вроде:

Код: Выделить всё

import os
import ctypes

class HandlerPointer(ctypes.c_void_p):
@staticmethod
def ffi(lib_path = os.path.abspath('mylib.so')):
lib = ctypes.CDLL(lib_path)
lib.create.argtypes = []
lib.create.restype = HandlerPointer
lib.process.argtypes = [HandlerPointer]
lib.process.restype = ctypes.c_int
lib.free.argtypes = [HandlerPointer]
lib.free.restype = None
return lib

def __init__(self):
super().__init__()
self.value = self.lib.create().value

def process(self):
return self.lib.process(self)

def __del__(self):
self.lib.free(self)

# can't do this var init inside the class as can't refer yet to HandlerPointer inside `.ffi()` if class not initialized yet
HandlerPointer.lib = HandlerPointer.ffi() # otherwise
UPD: похоже, что метод __init__ работает, за исключением метода __del__ (который вызывает пользовательский бесплатный метод C-land), существование которого приведет к сбою с двойным освобождением или повреждению (!prev). Нашел проблему, исправление описано в моем комментарии ниже, скоро опубликую полное решение.


Подробнее здесь: https://stackoverflow.com/questions/788 ... c-function

Вернуться в «Python»