将多个C ++类包装到一个Python类中

时间:2017-06-28 16:43:34

标签: python c++ cython

Cython允许通过包装其函数和类来使用C和C ++库。我想使用的两个库是SFML和Box2D。它们定义了单独的Vector2类。是否可以为这两个库(可能更多)编写一个Vector2 Python包装器?我的目标是在与不同的库交互时使用单一Python类型的Vector2。

有人做过类似的事吗?这将简化事情并统一我的Python API。我已经包装了SFML的部分内容,但除此之外我还不熟悉Cython。

参考SFML's Vector2如下所示:

template <typename T> class Vector2 {
    public:
        T x;
        T y;
        Vector2();
        Vector2(T X, T Y);
        template <typename U> explicit Vector2(const Vector2<U>& vector);
        ...
};

Box2D vector

struct b2Vec2 {
    float32 x, y;
    b2Vec2() {}
    b2Vec2(float32 xIn, float32 yIn);
    ...
};

1 个答案:

答案 0 :(得分:1)

<强>概述

一般的想法是三个步骤:

  1. 为您的类型编写声明
  2. 使用相同的界面单独包装每个班级
  3. 编写一个通用的矢量包装器
  4. <强>声明

    首先,您需要为包装类型提供Cython声明。一个例子(非常小)如下。

    # This is the Cython interface for Vector2
    
    cdef float float32 
    
    cdef extern from "Vector2.hpp" nogil:
        # if this was an stl vector, use vector[T, ALLOCATOR=*]
        # you must list every template type, even one with default values
        cdef cppclass Vector2[T]:   
            ctypedef T value_type
    
            # Add all the overloads, for example, multiplication
            Vector2[T, ALLOCATOR] operator*(const T&) const;
    
    
    cdef extern from "b2Math.h" nogil:
        cdef cppclass b2Vec2:
    
            # Add all overloads, for example, multiplication
            void operator*=(float)
    

    <强>接口

    接下来,您需要将这些包装到Python包装器中。您需要确保它们具有相同的接口,因此可以像其他接口一样使用。 Python data model是你的朋友。一个非常简单的例子是:

    cdef class SfmlVector2_32:
        # This is a definition for a float32 vector from Sfml
        Vector2[float32] c
    
        def __mul__(self, float32 x):
            # multiple and assign
            B2Vector2_32 copy;
            copy.c = c * x
            return copy;
    
    cdef class B2Vector2_32:
        # This is a definition for a float32 vector from box2
        b2Vec2 c
    
        def __mul__(self, float32 x):
            # multiple and assign
            B2Vector2_32 copy;
            copy.c = c;
            copy.c *= x
            return copy
    

    广义矢量

    最后,您需要一个简单的包装器类,它绑定许多矢量类型之一并在类上执行正确的操作。由于Python不是静态类型的,并且由于您包装的每个向量的接口都是相同的,因此这很简单:只需在__init__中初始化正确的向量。

    class Vector2_32:
    
        def __init__(self, framework = 'SFML'):
            # ideally, perform a dictionary lookup if you have many classes
            # O(1) for dict, if/then is O(n)
            if framework == 'SFML':
                self.vector = SfmlVector2_32()
            elif framework == 'BOX2':
                self.vector = B2Vector2_32()
            else:
                raise TypeError("Unrecognized framework.")
    
        def __mul__(self, float32 x):
            Vector2_32 copy
            copy.vector = vector * x
            return copy
    

    <强>思想

    这是一个非常糟糕的例子,因为通常你会根据__mul__(就地乘法)实现__imul__(乘法),但它会得到一般的想法。此代码中可能存在拼写错误,我现在无法访问计算机进行编译。