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標準庫
    • 靜態成員方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章