Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SWIG将C库与Python接口(SWIG生成的类使用起来很麻烦)_Python_C_Swig_Python Extensions - Fatal编程技术网

SWIG将C库与Python接口(SWIG生成的类使用起来很麻烦)

SWIG将C库与Python接口(SWIG生成的类使用起来很麻烦),python,c,swig,python-extensions,Python,C,Swig,Python Extensions,我正在使用SWIG生成到我的C库的Python语言绑定。我已经成功地构建了绑定和导出的数据结构,但在使用该库时,我不得不克服一些困难 例如,C标头具有如下数据类型和函数原型: struct MyStruct { /* fields */ } struct MyStruct * MYSTRUCT_Alloc(void); void MYSTRUCT_Free(struct MyStruct *); struct MyStruct * MYSTRUCT_Clone(const stru

我正在使用SWIG生成到我的C库的Python语言绑定。我已经成功地构建了绑定和导出的数据结构,但在使用该库时,我不得不克服一些困难

例如,C标头具有如下数据类型和函数原型:

struct MyStruct
{
    /* fields */
} 

struct MyStruct * MYSTRUCT_Alloc(void);
void MYSTRUCT_Free(struct MyStruct *);
struct MyStruct  * MYSTRUCT_Clone(const struct MyStruct *);
int MYSTRUCT_Func1(const struct MyStruct *, const int);

/* and so on */
def gFuncWrapper(mystruct):
    return fb.gFunc(mystruct.ms)
在我的SWIG接口文件中,我导出函数和MyStruct数据类型。假设我的python扩展模块名为foobar,那么我可以编写如下python脚本:

#import foobar as fb

# The line below creates a Python class which is a wrapper to MyStruct. HOWEVER I cannot pass this class to a function like MYSTRUCT_Func1 until I have initialized it by calling MYSTRUCT_Alloc ...

ms = fb.MyStruct  

# This will fail (throws a Python exception)
# ret =  fb.MYSTRUCT_Func1(ms, 123)

# However this works
ms = fb.MYSTRUCT_Alloc()
ret =  fb.MYSTRUCT_Func1(ms, 123)
声明一个对象,然后在使用它之前分配一个指向它的指针是非常麻烦的(而且容易出错)。是否有更好的方法使用SWIG生成的类?。我正在考虑包装更高级别的类(或对SWIG生成的类进行子类化),以自动处理对象的创建和销毁(以及提供一些明显的成员函数,如MYSTRUCT_Func1()

但是,如果我对SWIG生成的类进行了包装/子类化,那么我不确定是否可以将新类传递给需要指向C结构的指针的C API函数。我不能直接修改SWIG生成的类(或者至少不应该修改),原因很明显


解决这个问题的最佳方法是什么?一种更具Python风格的创建/销毁对象的方法,同时能够将指针直接传递到公开的C函数?

在Python端编写包装器对我来说似乎是个好主意,但不确定为什么您认为这样做行不通

class MyStructWrapper:
    def __init__(self):
        self.ms = fb.MYSTRUCT_Alloc()

    def __del__(self):
        fb.MYSTRUCT_Free(self.ms)

    def func1(self, arg):
        return fb.MYSTRUCT_Func1(self.ms, arg)
如果需要访问结构的成员,那么可以使用
self.ms.member
或编写getter和setter

您还可以将
克隆
功能安装到此设计中

编辑:关于您的评论,假设您有一个全局函数,它的指针指向
MyStruct

int gFunc(MyStruct* ms);
在Python端,您可以编写如下包装器:

struct MyStruct
{
    /* fields */
} 

struct MyStruct * MYSTRUCT_Alloc(void);
void MYSTRUCT_Free(struct MyStruct *);
struct MyStruct  * MYSTRUCT_Clone(const struct MyStruct *);
int MYSTRUCT_Func1(const struct MyStruct *, const int);

/* and so on */
def gFuncWrapper(mystruct):
    return fb.gFunc(mystruct.ms)

我希望这会有所帮助。

您可以将SWIG生成的模块命名为
\u foobar
,并编写一个纯Python模块
foobar
,该模块定义了必要的pythonic接口,例如,
openssl
包装器遵循该方法

另一个选项是使用Cython直接在C中创建接口:

cdef class MyStruct:
    cdef MyStruct_ptr this

    def __cinit__(self):
        self.this = MYSTRUCT_Alloc();
        if self.this is NULL:
           raise MemoryError

    def __dealloc__(self):
        if self.this is not NULL:
            MYSTRUCT_Free(self.this)

    def func1(self, n):
        return MYSTRUCT_Func1(self.this, n)
这将创建Python C扩展类型
MyStruct
,可从Python中用作:

ms = Mystruct()
print(ms.func1(123))
有关完整示例,请参见。

您的代码:

ms = fb.MyStruct

# This will fail (throws a Python exception) 
# ret =  fb.MYSTRUCT_Func1(ms, 123) 
仅将类分配给
ms
,而不是类的实例,这就是注释行失败的原因。以下操作应有效:

ms = fb.MyStruct()
ret =  fb.MYSTRUCT_Func1(ms, 123) 

我也有自由(非成员)函数,它们期望C struct ptr作为参数。目前,我可以将SWIG生成的类传递给那些公开的C函数。我可以类似地将MyStructRapper传递给这些函数吗?如果没有,是否有“特殊方法”例如,我可以在包装类上实现的值,以便在传递给需要C结构指针的函数时返回原始指针?当然,您需要为全局函数创建Python包装函数。这些函数将使用Python包装类,但将ms成员发送到C函数。我将更新我的回答是用一个例子。考虑使用cType来访问你的库而不是SWIG。啊,这样我就错了(我是一个Python Nebe)。它现在工作正常。最后一件事。我想给MyStultSub()类添加新的行为和方法。但关键的是,我仍然希望能够通过“增强类”。到需要原始指针的函数(目前,我可以将自动生成的MyStruct类传递给需要原始指针的导出C函数)。显然,我不能直接修改生成的代码,所以我尝试将MyStruct子类化,但当我将新类传递给我的C函数时,我得到了类型为“struct MyStruct*”的TypeError异常参数1。我想在MyStruct周围提供一个包装器的另一个原因是为了能够正确地销毁它。它是一个嵌套结构和一些函数实际上,从堆中分配内存-因此它被正确地销毁,以避免MEM泄漏。您是否考虑编写C++类并使用SWIG来暴露它?然后,您可以定义适当的构造函数和析构函数并添加其他方法。SWIG将将该类平坦化为C方法并提供Python包。每个类都是在Python中再次扮演一个类。马克说的是个好主意。我对这个问题的回答是在Python方面做这样的事情。如果你觉得在C++上比Python更舒服,在C++上做的更好。我觉得你都对。我已经写了C++的包装。C库以便于从Python中使用。我将接受马克的回答,因为他指出了如何从Python中使用库,并建议使用C++包装器简化事情。