在C++中嵌入Cython类方法

Embedding Cython Class Methods in C++

本文关键字:Cython 类方法 C++      更新时间:2023-10-16

我正试图在C++类中嵌入一个Cython类。考虑到项目的限制,为这个C++类创建Cython包装器是不可能的。由于Cython类中方法的数量和Cython类长时间的继承,从类中完全删除该方法并不是一个有吸引力的解决方案。我有必要创建一个Cython类实例,并从C++调用它的方法。然而,我似乎不能让它不出错。这里有一个问题的例子:

<lt<文件: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)

<lt<文件: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<文件: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(),也会导致其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)所需要的。生成的文件如下所示:

<lt<文件: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)

<lt<文件: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打印到stdout,这是正确的结果。我希望使用这个想法的一个更复杂的版本来替换在我的代码中对boost::python的一些调用,以提高性能。

在一个更复杂的设置中使用了前面提到的技术并反复获得segfault之后,这里是我使用的另一种方法。关键区别在于pyx文件中的apipublic关键字,以及如何在foo.cpp中包括和使用类。

<lt<文件: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)

<lt<文件: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();
}