在 C++ 中嵌入 Cython Class 方法

Embedding Cython Class Methods in C++

我正在尝试将 Cython class 嵌入到 C++ class 中。鉴于项目的限制,无法为此 C++ class 创建 Cython 包装器。并且由于 Cython classes 中的方法数量和 Cython classes 的长期继承,完全从 class 中删除方法并不是一个有吸引力的解决方案。我有必要创建一个 Cython class 实例并从 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();
}

<<< 文件:setup.py >>>

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 是成功的。我知道我在 foobar() 中打印 foo.afoo.b 的值,但是一旦我使用 foobar() 中的 Foo 对象进行调用,程序段错误。即使在 foobar() 中调用 foo.__dict__foo.callable() 也会导致它出现段错误。更改 publicapi 关键字有效果,在 __init____cinit__ 之间切换也没有效果。如果有人知道如何解决这个问题,我将不胜感激。我怀疑它与指针或滥用 Python C API 有关。非常感谢!

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

<<< 文件: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 Foo buildFoo(double a, double b):
    return Foo(a,b)

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 = buildFoo(10.0,5.0);
    std::cout << foobar(foo,5.0) << "\n";
    Py_Finalize();
}

使用相同的 setup.py 脚本。

运行 这导致 -0.262375 打印到标准输出,这是正确的结果。我希望使用这个想法的更复杂版本来替换我整个代码中对 boost::python 的一些调用,以提高性能。

在更复杂的设置中使用前面提到的技术并反复出现段错误后,这是我使用的替代方法。关键区别在于 pyx 文件中的 apipublic 关键字,以及 foo.cpp.

中包含和使用 class 的方式。

<<< 文件: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 public Foo buildFoo(double a, double b):
    return Foo(a,b)

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

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

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