是否可以使用ctypes将字节和bytearray对象有效地传递给外部库?

时间:2017-05-09 10:42:40

标签: python python-2.7 ctypes

假设我在外部库中有以下功能:

void foo(const unsigned char *buf, const int len);

我希望能够使用ctypes从我的Python代码中调用此函数,而无需复制缓冲区。缓冲区可能非常大,因此避免复制具有明显的性能优势。为了方便我的代码使用者,我希望能够以bytesbytearray提供此缓冲区。

目前,我在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互换?

1 个答案:

答案 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的数组类型。