我请求您的帮助,因为我正在尝试运行一个cython示例,它比许多教程(例如this guide)中可能包含一个类的cython示例要复杂得多。我还没有找到任何“更高级的”教程,所以我希望这个问题对试图深入学习它的人也有用。
我将在此处写下我采取的步骤,希望有人能告诉我我的错误在哪里。
我有一个 Rectangle c ++类(我在这里只是放了.h文件以使其更短):
#ifndef RECTANGLE_H
#define RECTANGLE_H
namespace shapes {
class Rectangle {
public:
int x0, y0, x1, y1;
Rectangle();
Rectangle(int x0, int y0, int x1, int y1);
~Rectangle();
int getArea();
};
}
#endif
和 Group2 类。一个非常简单的示例类,其构造函数将2个矩形作为输入:
#ifndef GROUP4_H
#define GROUP4_H
#include "Rectangle.h"
namespace shapes{
class Group2 {
public:
Rectangle rect0, rect1, rect2, rect3 ;
Group2();
Group2(Rectangle rect0, Rectangle rect1);
~Group2();
void getAreas(int *area0, int *area1);
};
}
#endif
然后我创建一个 grp2.pyx 文件,同时定义 Rectangle 和 Group2 类:
#RECTANGLE
cdef extern from "Rectangle.h" namespace "shapes":
cdef cppclass Rectangle:
Rectangle() except +
Rectangle(int, int, int, int) except +
int x0, y0, x1, y1
int getArea()
cdef class PyRectangle:
cdef Rectangle c_rect
def __cinit__(self, int x0, int y0, int x1, int y1):
self.c_rect = Rectangle(x0, y0, x1, y1)
def get_area(self):
return self.c_rect.getArea()
# GROUP2
cdef extern from "Group2.h" namespace "shapes":
cdef cppclass Group2:
Group2() except +
Group2(Rectangle rect0, Rectangle rect1) except +
void getAreas(int *area0, int *area1)
cdef class PyGroup2:
cdef Group2 c_group2
def __cinit__(self, Rectangle rect0, Rectangle rect1):
self.c_group2 = Group2(rect0, rect1)
def get_areas(self):
cdef int area0, area1
self.c_group2.getAreas(&area0, &area1)
return area0, area1
然后我使用命令行在静态c ++库中编译这两个类:
gcc -c -fPIC Group2.cpp Rectangle.cpp
和
ar rcs libexample.a Group2.o Rectangle.o
最后,我创建从命令行调用的cython setup.py 文件:
from distutils.core import setup, Extension
from Cython.Build import cythonize
setup(ext_modules = cythonize(Extension(
name="grp2", # the extension name
sources=["grp2.pyx"], # the Cython source and
libraries=["example"],
library_dirs=["lib"],
include_dirs=["lib"],
# additional C++ source files
language="c++", # generate and compile C++ code
)))
这时我在 PyGroup2 的 _cinint _ 中出现错误:
无法将Python对象参数转换为“矩形”类型
我想我的pyx文件中有一些错误,但是我不能说出什么,因为我在那里定义了python的 Rectangle 。
答案 0 :(得分:1)
在将矩形传递给C ++函数时,应在PyRectangle
函数的签名中使用def
,并在PyRectangle.c_rect
的签名中使用。{p>
这意味着您的代码应为:
cdef class PyGroup2:
...
def __cinit__(self, PyRectangle rect0, PyRectangle rect1):
self.c_group2 = Group2(rect0.c_rect, rect1.c_rect)
请继续阅读,以详细了解原因。
传递给def
-函数的所有参数都是Python对象(即Cython-parlance中的object
类型),之后所有这些函数都将从纯Python(仅知道Python对象)进行调用
例如,您可以添加一些语法糖并在def
函数的签名中使用“ late-binding”代替
def do_something(n):
...
使用
def do_something(int n):
...
在后台,Cython会将这段代码转换为类似以下内容:
def do_something(n_):
cdef int n = n_ # conversion to C-int
...
对于int
或double
之类的内置类型,此自动转换是可能的,因为Python-C-API中有这些转换的功能(即PyLong_AsLong
,{{3} }。 Cython还处理错误检查,因此您不应该手动进行这些转换。
但是,对于像Rectangle
类这样的用户定义类型/类,这种自动转换是不可能的-Cython只能自动转换为cdef
-类/扩展名,即PyRectangle
,因此应在签名中使用PyRectangle
:
cdef class PyGroup2:
...
def __cinit__(self, PyRectangle rect0, PyRectangle rect1):
...
Cython负责从object
到PyRectangle
的转换之后,必须通过利用PyRectangle
手动完成从Rectangle
到c_rect
的最后一步-指针:
...
def __cinit__(self, PyRectangle rect0, PyRectangle rect1):
self.c_group2 = Group2(rect0.c_rect, rect1.c_rect)
cpdef
函数的规则相似,因为可以从纯Python调用它们。 PyFloat_AsDouble
仅适用于Cython可以自动覆盖Python对象的类型。
不出所料,唯一可以在其签名中包含C ++类的函数是cdef
函数。