我正在尝试设计一个C接口,可以轻松地在Python中进行扩展(使用ctypes)。我在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);
};
如果我想要直接从C扩展这个接口,它可以很好地工作:
struct derived /* concrete implementation */
{
struct format base;
};
但是我真正想做的是,使用ctypes从Python实现此接口。以下是我的实现代码:
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
我在这里努力地定义OPENFUNC
的原型。技术上来说,它应该是:
OPENFUNC = ctypes.CFUNCTYPE(ctypes.POINTER(python_format), ctypes.c_char_p)
然而,我需要先定义python_format
,这又需要对OPENFUNC
进行定义。
附加问题:实际上应该如何实现此函数?例如:
def func( str ): return None
或者
def func( str ): i = python_format(); return ctypes.pointer(i)
都给我:
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
这是否与另一个问题有关?如果是,那么我应该更改我的初始C设计,因为我将无法从回调中返回对python_format
实例的指针吗?
open
应该返回已分配的实例。理想情况下,在 Python 中,open
的实现应该简单地return self
或return ctypes.pointer(self)
。由于垃圾回收器,delete
在 Python 中将不起作用。 - malatTypeError
消息,这个消息并不是很有帮助。回调的结果类型必须在其StgDictObject
(常规PyDictObject
的ctypes扩展)中具有setfunc
。此要求限制您只能使用简单类型,例如c_void_p
,并且回调函数应返回ctypes.addressof(self)
。 - Eryk Sun