在C ++中嵌入Cython类方法

时间:2016-04-06 15:17:43

标签: python c++ cython

我试图在C ++类中嵌入一个Cython类。考虑到项目的约束,不可能为此C ++类创建Cython包装器。由于Cython类中的方法数量和Cython类的长继承性,完全从类中删除方法并不是一个有吸引力的解决方案。我有必要创建一个Cython类实例并从C ++调用它的方法。但是,我似乎无法使其成为段错误。以下是问题的一个示例:

<<<文件:fooClass.pyx>>>

from math import sin
cdef public class Foo[object Foo, type fooType]:
    cdef double a,b  
    def __cinit__(self, double a, double b):
        self.a = a
        self.b = b  
    cdef double bar(self, double c):
        return sin(self.a*c)  
cdef api double foobar(Foo foo, double d):
    return foo.bar(d)

<<<文件:Foo.cpp>>>

#include "fooClass_api.h"
#include <iostream>

int main(){
    Py_Initialize();
    import_fooClass();
    Foo foo;
    foo.a = 1.0;
    foo.b = 10.0;
    std::cout << foobar(&foo,5.0) << "\n";
    Py_Finalize();
}

&LT;&LT;&LT;文件:setup.py&gt;&gt;&gt;

from distutils.core import setup
from Cython.Build import cythonize  
setup ( ext_modules = cythonize ("cyClass.pyx"))

我用python setup.py build_ext --inplace构建并使用g ++编译。通过测试,我知道Py_Initialize()import_fooClass正在取得成功。我知道我在foo.a内打印foo.bfoobar()的值,但只要我使用Foo内的foobar()对象拨打电话,程序段错误。即使在foo.__dict__内拨打foo.callable()foobar(),也会导致其发生段错误。更改publicapi个关键字已生效,也未在__init____cinit__之间切换。如果有人知道如何解决这个问题,我会非常感激。我怀疑它与指针或滥用Python C API有关。非常感谢!

2 个答案:

答案 0 :(得分:1)

我设法解决了这个问题。基于David W所说的内容(感谢David!),我创建了另一个cdef api类来充当构造函数的包装器,cdef api Foo buildFoo (double a, double b):这将返回一个Foo*指针,该指针需要.pyx文件中的foobar(Foo foo, double d)。生成的文件如下所示:

&LT;&LT;&LT;文件:fooClass.pyx&gt;&gt;&gt;

from math import sin

cdef public class Foo[object Foo, type fooType]:
    cdef double a,b  

    def __cinit__(self, double a, double b):
        self.a = a
        self.b = b  

    cdef double bar(self, double c):
        return sin(self.a*c)  

cdef api Foo buildFoo(double a, double b):
    return Foo(a,b)

cdef api double foobar(Foo foo, double d):
    return foo.bar(d)

&LT;&LT;&LT;文件:Foo.cpp&gt;&gt;&gt;

#include "fooClass_api.h"
#include <iostream>

int main(){
    Py_Initialize();
    import_fooClass();
    Foo *foo = buildFoo(10.0,5.0);
    std::cout << foobar(foo,5.0) << "\n";
    Py_Finalize();
}

使用相同的setup.py脚本。

运行此结果会将-0.262375打印到stdout,这是正确的结果。我希望在我的代码中使用更复杂的这个想法来替换对boost :: python的一些调用,以提高性能。

答案 1 :(得分:1)

在更复杂的设置中使用前面提到的技术并反复获取段错误后,这是我使用的替代方法。关键区别在于api文件中的publicpyx关键字以及foo.cpp中如何包含和使用该类。

&LT;&LT;&LT;文件:fooClass.pyx&gt;&gt;&gt;

from math import sin

cdef public class Foo[object Foo, type fooType]:
    cdef double a,b  
    def __cinit__(self, double a, double b):
        self.a = a
        self.b = b  
    cdef double bar(self, double c):
        return sin(self.a*c)  

cdef public Foo buildFoo(double a, double b):
    return Foo(a,b)

cdef public double foobar(Foo foo, double d):
    return foo.bar(d)

&LT;&LT;&LT;文件:Foo.cpp&gt;&gt;&gt;

#include <Python.h>
#include "fooClass.h"
#include <iostream>

int main(){
    Py_Initialize();
    initfooClass();
    Foo *foo = buildFoo(10.0,5.0);
    std::cout << foobar(foo,5.0) << std::endl;
    Py_Finalize();
}