я определил ctypes
класс и связанный с ним удобство функции, как так:Чистый способ структурирования ctypes класса
class BNG_FFITuple(Structure):
_fields_ = [("a", c_uint32),
("b", c_uint32)]
class BNG_FFIArray(Structure):
_fields_ = [("data", c_void_p),
("len", c_size_t)]
# Allow implicit conversions from a sequence of 32-bit unsigned ints
@classmethod
def from_param(cls, seq):
return seq if isinstance(seq, cls) else cls(seq)
def __init__(self, seq, data_type = c_float):
array_type = data_type * len(seq)
raw_seq = array_type(*seq)
self.data = cast(raw_seq, c_void_p)
self.len = len(seq)
def bng_void_array_to_tuple_list(array, _func, _args):
res = cast(array.data, POINTER(BNG_FFITuple * array.len))[0]
return res
convert = lib.convert_to_bng
convert.argtypes = (BNG_FFIArray, BNG_FFIArray)
convert.restype = BNG_FFIArray
convert.errcheck = bng_void_array_to_tuple_list
drop_array = lib.drop_array
drop_array.argtypes = (POINTER(BNG_FFIArray),)
я затем определить простую функцию удобства:
def f(a, b):
return [(i.a, i.b) for i in iter(convert(a, b))]
Большинство этих работ но у меня есть два вопроса:
- Это не достаточно гибкий; Я хотел был бы иметь возможность создать экземпляр
BNG_FFITuple
, используяc_float
вместоc_uint32
(так что поляc_float
), и наоборот,BNG_FFIArray
data_type
-c_uint32
. Однако я не знаю, как это сделать. - Я хочу освободить память, которая теперь принадлежит Python, отправив
POINTER(BNG_FFIArray)
обратно в мой dylib (см.drop_array
- Я уже определил функцию в своем dylib), но я не уверен, что Я должен это назвать.
Есть ли способ инкапсулировать все это в более аккуратный, более Pythonic способ, который также безопаснее? Я обеспокоен тем, что без очистки памяти определяется в прочном образом (на __exit__
? __del__
?), Что все, что идет не так, приведет к unfreed памяти
Вам нужен 'BNG_FFITuple' как аргумент FFI или он предназначен только для использования в Python? Если это просто используется в Python, вам лучше будет работать [collection.namedtuple] (https://docs.python.org/3/library/collections.html#collections.namedtuple). Просто определите отдельную функцию 'errcheck' для конверсий' int' и 'float'. Вы можете освободить массив в 'BNG_FFIArray .__ del__', но используйте ссылку на класс' lib.drop_array' как 'BNG_FFIArray._drop_array', чтобы избежать проблем с установкой модуля' lib' в 'None' перед финализатором' __del__' объекта ха. – eryksun
Я не уверен, что понимаю; мои функции dylib ожидают структуру с полями 'data' и' len' с соответствующими типами, но ее не нужно называть чем-то конкретным. – urschrei
Вы преобразовываете результат в массив 'BNG_FFITuple' в' bng_void_array_to_tuple_list'. Вы когда-нибудь передавали 'BNG_FFITuple' обратно в свою библиотеку? Если нет, нет причин использовать структуру ctypes для этого вместо преобразования результата в обычный кортеж Python или 'namedtuple'. После преобразования 'BNG_FFIArray' является единственной ссылкой на массив, поэтому отлично использовать финализатор' __del__' для вызова 'drop_array'. – eryksun