在 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.a
和 foo.b
的值,但是一旦我使用 foobar()
中的 Foo
对象进行调用,程序段错误。即使在 foobar()
中调用 foo.__dict__
或 foo.callable()
也会导致它出现段错误。更改 public
或 api
关键字有效果,在 __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
文件中的 api
和 public
关键字,以及 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();
}
我正在尝试将 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.a
和 foo.b
的值,但是一旦我使用 foobar()
中的 Foo
对象进行调用,程序段错误。即使在 foobar()
中调用 foo.__dict__
或 foo.callable()
也会导致它出现段错误。更改 public
或 api
关键字有效果,在 __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
文件中的 api
和 public
关键字,以及 foo.cpp
.
<<< 文件: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();
}