J'essaie de concevoir une interface C qui pourrait facilement être étendue en Python (en utilisant ctypes). Je l'ai utilisé le natural idiom dans C:Classe auto-référencée: classe Python concrète de l'interface C
struct format {
int (*can_open)(const char *filename);
struct format * (*open)(const char *filename);
void (*delete)(struct format *self);
int (*read)(struct format *self, char *buf, size_t len);
};
Il fonctionne très bien si je veux étendre cette interface de C directement:
struct derived /* concrete implementation */
{
struct format base;
};
Mais ce que je voudrais vraiment faire, est de mettre en œuvre cette interface à partir de Python en utilisant ctypes. Voici ce que j'ai jusqu'à présent:
CANOPENFUNC = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_char_p)
#OPENFUNC = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p)
#OPENFUNC = ctypes.CFUNCTYPE(ctypes.POINTER(python_format), ctypes.c_char_p)
#DELETEFUNC = ctypes.CFUNCTYPE(None, ctypes.c_void_p)
#READFUNC = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p)
def py_canopen_func(string):
print "py_canopen_func", string
return 1
canopen_func = CANOPENFUNC(py_canopen_func)
#open_func = OPENFUNC( py_open_func)
#delete_func = DELETEFUNC(py_canopen_func)
#read_func = READFUNC(py_canopen_func)
class python_format(ctypes.Structure):
_fields_ = (
('can_open', CANOPENFUNC),
('open', OPENFUNC),
('delete', DELETEFUNC),
('read', READFUNC),
)
def __init__(self):
self.can_open = canopen_func
OPENFUNC = ctypes.CFUNCTYPE(ctypes.POINTER(python_format), ctypes.c_char_p)
def py_open_func2(string):
print "py_open_func2", string
return ctypes.byref(self)
self.open = OPENFUNC(py_open_func2)
#self.delete = delete_func
#self.read = read_func
Vraiment, je me bats pour définir le prototype de OPENFUNC
ici. Techniquement, il devrait être:
OPENFUNC = ctypes.CFUNCTYPE(ctypes.POINTER(python_format), ctypes.c_char_p)
Cependant, je dois définir python_format
d'abord, qui à son tour nécessite une définition pour OPENFUNC
.
Point bonus: qu'est-ce qu'une implémentation de fonction réelle? Par exemple:
def func(str): return None
ou
def func(str): i = python_format(); return ctypes.pointer(i)
deux me donne:
class python_format(ctypes.Structure):
pass
OPENFUNC = ctypes.CFUNCTYPE(ctypes.POINTER(python_format), ctypes.c_char_p)
OPENFUNC(func)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: invalid result type for callback function
Est-ce lié à cette autre issue? Si oui, devrais-je changer ma conception C initiale, puisque je ne serai pas capable de retourner un pointeur vers une instance python_format
à partir d'un rappel?
correcte. 'open' est destiné à renvoyer l'instance allouée. Idéalement, l'implémentation de 'open' en python, devrait être simple' return self' ou 'return ctypes.pointer (self)'. 'delete' sera un no-op en python à cause du garbage collector. – malat
Le message 'TypeError' que vous obtenez lorsque vous essayez d'utiliser un type non-simple à la suite d'un rappel est moins utile. Un type de résultat de callback doit avoir un 'setfunc' dans son' StgDictObject' (une extension ctypes du 'PyDictObject' normal). Cette exigence vous limite à l'utilisation d'un type simple tel que 'c_void_p', et la fonction de rappel doit renvoyer' ctypes.addressof (self) '. – eryksun