Cython--使用Cython封装C++代码(四)

mac2022-06-30  24

Using C++ in Cython

Cython对C++语言的大部分特性都支持,例如:

可以通过new和del关键字在堆区动态创建和消耗对象可以在栈区创建对象也可以通过Cython提供的cppclass关键字声明类类型Cython支持函数模板(template function)和类模板(template class),函数重载Cython支持C++操作符重载(eg: operator+,operator[] …)

通过Cython封装一个C++文件的大致步骤

1、在setup.py脚步文件中指定C++语言或指名C++源文件2、创建一个或多个.pxd文件,并用cdef extern from blocks 和C++命名空间名。在每个blocks中: 使用cppclass声明类将成员变量、方法、构造方法声明为公有的(public) 3、在.pyx文件中,通过cimport导入上面的这些扩展模块

C++ API 封装示例:

1、实现一个C++ API,用于计算矩形面积的。

新建头文件Rectangle.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(); void getSize(int* width, int* height); void move(int dx, int dy); }; } #endif

新建对应的类类型实现文件Rectangle.cpp

#include "Rectangle.h" namespace shapes { // 默认构造 Rectangle::Rectangle () {} // 有参构造 Rectangle::Rectangle (int x0, int y0, int x1, int y1) { this->x0 = x0; this->y0 = y0; this->x1 = x1; this->y1 = y1; } // 析构函数 Rectangle::~Rectangle () {} // 获取矩形的面积 int Rectangle::getArea () { return (this->x1 - this->x0) * (this->y1 - this->y0); } // 获取矩形的长宽 // Put the size in the pointer args void Rectangle::getSize (int *width, int *height) { (*width) = x1 - x0; (*height) = y1 - y0; } // 移动矩形位置 void Rectangle::move (int dx, int dy) { this->x0 += dx; this->y0 += dy; this->x1 += dx; this->y1 += dy; } }

2、在Cython声明上述的成员,Cython将这些声明放在Rectangle.pxd文件,可以将它看着是Cython可读的头文件。

cdef extern from "Rectangle.cpp": pass # Declare the class with cdef 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() void getSize(int* width, int* height) void move(int, int)

第1~2两行是显示指明包含C++的代码文件,也可以在这里写,再后续的.pyx文件中通过如下代码指明也可以。

# distutils: sources = Rectangle.cpp

3 最后一步,通过Cython开放Rectangle接口,新建rect.pyx文件

# distutils: language = c++ from Rectangle cimport Rectangle # Create a Cython extension type which holds a C++ instance # as an attribute and create a bunch of forwarding methods # Python extension type. cdef class PyRectangle: cdef Rectangle c_rect # Hold a C++ instance which we're wrapping 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() def get_size(self): cdef int width, height self.c_rect.getSize(&width, &height) return width, height def move(self, dx, dy): self.c_rect.move(dx, dy)

第一行的# distutils: language = c++是显示告诉Cython按照C++语言编译。

4 脚本编译setup.py

from distutils.core import setup from Cython.Build import cythonize setup(ext_modules=cythonize("rect.pyx"))

编译链接: python3 setup.py build_ext --inplace 生成rect.xxx.so文件

5 接口测试,当前目录下终端python3或ipython3

import rect x0, y0, x1, y1 = 1, 2, 3, 4 rect_obj = rect.PyRectangle(x0, y0, x1, y1) print(dir(rect_obj)) print('矩形长宽: ',rect_obj.get_size()) #矩形长宽: (2, 2) print('矩形面积: ',rect_obj.get_area()) 矩形长宽: (2, 2)

总结

展望

函数重载操作符重载模板CPP标准库静态成员方法
最新回复(0)