Python C扩展,将胶囊暴露给ctypes以使用第三方C代码

问题描述 投票:1回答:1

我有一个Python C扩展程序,用于包装专有产品的库。我们公司有大量使用专有产品的C代码。没想到不用使用C扩展在Python中重写此代码,而是让我简单地将Capsule返回到Python领域,并允许我的库用户使用ctypes包装一些C函数。

这是有效的方法吗?有更好的吗?

这里有一些代码来说明我的方法。

我的Python C扩展名:

typedef struct {
    PyObject_HEAD

    Foo *foo; /* The proprietary data structure we are wrapping */
} PyFoo;

/*
* Expose a pointer to Foo such that ctypes can use it
*/
static PyObject PyFoo_capsule(PyFoo *self, PyObject *args, PyObject *kwargs)
{
     return PyCapsule_New(self->foo, "foo", NULL);
}

这里是我们团队编写的一些已有的C代码,想从Python调用:

void print_foo(Foo *foo)
{
    Foo_print(foo);
}

并且在Python中,我们可以使用ctypes包装第三方C代码(我学到了here):

import pyfoo
import ctypes

foo = pyfoo.Foo()
capsule = foo.capsule()

ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object, ctypes.c_char_p]
pointer = ctypes.pythonapi.PyCapsule_GetPointer(
    capsule, 
    ctypes.create_string_buffer("foo".encode())
)

libfoo = ctypes.CDLL('libfoo.so')
libfoo.print_foo.restype = None
libfoo.print_foo.argtypes = [ctypes.POINTER(None)]
libfoo.print_foo(pointer)
python python-3.x ctypes python-c-api
1个回答
0
投票

它可以工作,但是我不喜欢对不透明类型使用void*的方法,因为任何void*都可以,而在C方面,类型很重要,您的诊断很可能是段错误(或更糟糕的是)是否传递了指向错误类型的指针。

大多数(自动)活页夹(SWIG,pybind11,C / C ++的cppyy或C的CFFI)将为不透明的C / C ++生成Python类型,以允许类型匹配。

这是一个cppyy(http://cppyy.org)示例,假设文件foo.h像这样:

struct Foo;
struct Bar;

typedef Foo* FOOHANDLE;
typedef Bar* BARHANDLE;

void use_foo(FOOHANDLE);
void use_bar(BARHANDLE);

和一些匹配的库libfoo.so,然后从cppyy中使用时,您只能通过FOOHANDLE参数等传递FOOHANDLE,以便获得干净的Python端回溯,而不是C端崩溃。会话示例:

>>> import cppyy
>>> cppyy.c_include("foo.h")     # assumes C, otherwise use 'include'
>>> cppyy.load_library("libfoo")
>>> foo = cppyy.gbl.FOOHANDLE()  # nullptr; can also take an address
>>> cppyy.gbl.use_foo(foo)       # works fine
>>> cppyy.gbl.use_bar(foo)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: void ::use_bar(Bar*) =>
    TypeError: could not convert argument 1
>>> 
© www.soinside.com 2019 - 2024. All rights reserved.