假设我在外部库中有以下功能:
void foo(const unsigned char *buf, const int len);
我希望能够使用ctypes
从我的Python代码中调用此函数,而无需复制缓冲区。缓冲区可能非常大,因此避免复制具有明显的性能优势。为了方便我的代码使用者,我希望能够以bytes
或bytearray
提供此缓冲区。
目前,我在buf
声明中声明ctypes.POINTER(ctypes.c_char)
为argtypes
。
lib.foo.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_int]
buf = bytes(...)
lib.foo(buf, len(buf))
这很好用,我可以传递bytes
个对象。但是,如果我传递bytearray
对象,则会遇到以下错误:
ctypes.ArgumentError:参数1 ::错误类型
我是否有办法允许bytearray
通过,最好与bytes
互换?
答案 0 :(得分:1)
您可以创建指针类型的子类,该子类覆盖from_param
以适应bytearray
。例如:
class Pchar(ctypes.POINTER(ctypes.c_char)):
_type_ = ctypes.c_char
@classmethod
def from_param(cls, param, array_t=ctypes.c_char * 0):
if isinstance(param, bytearray):
param = array_t.from_buffer(param)
return super(Pchar, cls).from_param(param)
lib.foo.argtypes = [Pchar, ctypes.c_int]
只需要通过Python的缓冲协议获取对象的内部缓冲区,为c_char
创建的bytearray
数组。数组大小无关紧要,因此我们可以避免为bytearray
的每个可能长度创建数组子类。只需使用在from_param
参数列表中缓存的长度为0的数组类型。