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

Using C++ in Cython

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

  • 可以通过newdel关键字在堆区动态创建和消耗对象
  • 可以在栈区创建对象
  • 也可以通过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标准库
    • 静态成员方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章