我试图将Cython类嵌入C++类。鉴于项目的限制,无法为此C++类创建Cython包装器。而且由于Cython类中方法的数量众多以及Cython类的长继承性,因此从类中完全删除该方法并不是一种有吸引力的解决方案。对我来说,有必要创建一个Cython类实例并从C++调用其方法。但是,我似乎无法使其不成为段错误。这是问题的示例:

<<>>

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)

<<>>
#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();
}

<<>>
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()的调用也会导致segfault。更改publicapi关键字没有效果,也没有在__init____cinit__之间切换。如果有人知道如何解决此问题,我将不胜感激。我怀疑这与指针或滥用Python C API有关。非常感谢!

最佳答案

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

<<>>

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)

<<>>
#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的一些调用,以提高性能。

10-08 07:55
查看更多