将多个C 类包装成一个Python类

Wrapping multiple C++ classes into one Python class

本文关键字:一个 Python 包装      更新时间:2023-10-16

cython允许通过包装其功能和类来使用C和C 库。我想使用的两个库是SFML和Box2D。他们定义了单独的vector2类。是否可以为这两个库编写一个Vector2 Python包装器(以及更多(?我的目标是在与不同库交互时具有单python类型的vector2。

有人已经做了类似的事情吗?这将简化事物并统一我的Python API。我已经包裹了SFML的一部分,但除此之外,我是Cython的新手。

对于参考SFML的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向量:

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

概述

一般想法是三个步骤:

  1. 为您的类型写声明
  2. 用相同的接口单独包装每个类
  3. 写一个广义矢量包装器

声明

首先,您需要包装类型的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数据模型是您的朋友。一个非常简单的例子是:

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

思想

这是一个非常糟糕的示例,因为通常您以__imul__(现场乘法(来实现__mul__(乘法(,但是它可以贯穿一般的想法。此代码可能有错别字,我现在无法访问机器来立即进行编译。