ja zdefiniował ctypes
klasę i wygodę przypisaną funkcję tak:Clean sposób strukturyzacji ctypes klasa
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),)
I następnie zdefiniować prostą funkcję Wygoda:
def f(a, b):
return [(i.a, i.b) for i in iter(convert(a, b))]
Większość tych prac idealnie, ale mam dwie kwestie:
- Nie jest wystarczająco elastyczny; Chciałbym móc utworzyć instancję używając
c_float
zamiastc_uint32
(więc pola sąc_float
) i odwrotnie, więcBNG_FFIArray
data_type
jestc_uint32
. Nie wiem jednak, jak to zrobić. - Chciałbym zwolnić pamięć, która jest teraz własnością Pythona, wysyłając
POINTER(BNG_FFIArray)
z powrotem do mojej dylib (patrzdrop_array
- Mam już zdefiniowaną funkcję w mojej dylib), ale nie jestem pewien, na co punkt, powinienem to nazwać.
Czy istnieje sposób hermetyzowania tego wszystkiego w sposób bardziej przejrzysty, bardziej Pythoniczny, który jest również bezpieczniejszy? Jestem zaniepokojony, że bez czyszczenia pamięci jest zdefiniowany w solidny sposób (na __exit__
? __del__
?) Że wszystko, co pójdzie nie tak, doprowadzi do braku pamięci
Czy potrzebujesz 'BNG_FFITuple' jako argumentu FFI, czy jest to tylko do użycia w Pythonie? Jeśli jest to po prostu używane w Pythonie, lepiej będzie Ci służyć [collections.namedtuple] (https://docs.python.org/3/library/collections.html#collections.namedtuple). Po prostu zdefiniuj oddzielną funkcję 'errcheck' dla konwersji' int' i 'float'. Możesz zwolnić tablicę w 'BNG_FFIArray .__ del__', ale użyj odwołania do klasy' lib.drop_array' jako 'BNG_FFIArray._drop_array' aby uniknąć problemów z odejściem modułu ustawienie' lib' na 'None' przed finalizatorem' __del__' obiektu Zostałem wezwany. – eryksun
Nie jestem pewien, czy rozumiem; moje funkcje dylib oczekują struktury z polami "data" i "len" z odpowiednimi typami, ale nie trzeba jej nazwać niczym konkretnym. – urschrei
Konwertujesz wynik na tablicę 'BNG_FFITuple' w' bng_void_array_to_tuple_list'. Czy kiedykolwiek przekazujesz 'BNG_FFITuple' do swojej biblioteki? Jeśli nie, nie ma powodu, aby używać struktury ctypes dla tego zamiast konwertowania wyniku do zwykłego "krotki" Pythona lub "nazwanego krotki". Po przekonwertowaniu 'BNG_FFIArray' jest jedynym odniesieniem do tablicy, więc dobrze jest użyć jego' __del__' finalizatora, aby wywołać 'drop_array'. – eryksun