Cython:无效的操作数类型

时间:2016-08-02 07:12:01

标签: python c++ cython

我有一个C ++类实现,我想用Cython向Python公开。 类接口是这样的(每个运算符的实现涉及一些私有属性,因此它们不能是内联实现):

class Quantity {

private:
// Some implementation -- 

public:

    explicit Quantity(...);
    Quantity(const Quantity &);
    ~Quantity(){};
    double operator()(const std::string) const;

    friend Quantity operator+ (const Quantity & a, const Quantity & b) {//implementation };
    friend Quantity operator- (const Quantity & a, const Quantity & b) {//implementation};
    friend Quantity operator* (const Quantity & a, const Quantity & b) {//implementation};
    friend Quantity operator/ (const Quantity & a, const Quantity & b) {//implementation};
    friend bool operator < (const Quantity & a, const Quantity & b) {//implementation};
    friend bool operator <= (const Quantity & a, const Quantity & b) {//implementation};
    friend bool operator > (const Quantity & a, const Quantity & b) {//implementation};
    friend bool operator >= (const Quantity & a, const Quantity & b) {//implementation};
    friend bool operator == (const Quantity & a, const Quantity & b) {//implementation};
    friend bool operator != (const Quantity & a, const Quantity & b) {//implementation};

};

.pxd(部分):

from libcpp.string cimport string
from libcpp cimport bool

cdef extern from "quantity.h" namespace "munits":

    cdef cppclass Quantity:
        Quantity(...)

        bool operator< (const Quantity &)
        double operator()(string)

        Quantity operator+(const Quantity &)

.pyx(部分):

cdef class PyQuantity:

    cdef :
        Quantity *_thisptr

    def __cinit__(PyQuantity self, ... ):
        self._thisptr = new Quantity(...)

    def __cinit__(PyQuantity self, Quantity ot):
        self._thisptr = new Quantity(ot)

    def __dealloc__(self):
        if self._thisptr != NULL:
            del self._thisptr

    cdef int _check_alive(self) except -1:
        if self._thisptr == NULL:
            raise RuntimeError("Wrapped C++ object is deleted")
        else:
            return 0

    def __enter__(self):
        self._check_alive()
        return self

    def __exit__(self, exc_tp, exc_val, exc_tb):
        if self._thisptr != NULL:
            del self._thisptr
            self._thisptr = NULL # inform __dealloc__
        return False # propagate exceptions

    def __richcmp__(PyQuantity self, PyQuantity other, op):
        if op == 0:
            return self._thisptr[0] < other._thisptr[0]


    def __add__(PyQuantity self, PyQuantity other):

        return new PyQuantity(self._thisptr[0] + other._thisptr[0])

operator()和所有比较运算符的实现都有效,但是对于其他数学运算符,比如'+',我无法正确运行。我还检查了此处描述的变体:Cython: Invalid operand types for '+' (btVector3; btVector3) 但我仍然得到无效的操作数类型或无法将'Quantity'转换为Python对象。我错过了什么,为什么其他运营商工作和增加而不是这样?

2 个答案:

答案 0 :(得分:0)

据我记得

,不允许多个__cinit__
def __cinit__(PyQuantity self, ... ):
    self._thisptr = new Quantity(...)

def __cinit__(PyQuantity self, Quantity ot):
    self._thisptr = new Quantity(ot)

__cinit__的参数应该是python对象(object,list,tuple,int,bint,double,PyQuantity,...)而不是C ++类Quantity。

def __cinit__(PyQuantity self, PyQuantity other=None):
    if other is not None:
        self._thisptr = new Quantity(other._thisptr[0])
    else:
        self._thisptr = new Quantity()

def __add__(PyQuantity self, PyQuantity other):
    return new PyQuantity(self._thisptr[0] + other._thisptr[0])

可能写成

def __add__(PyQuantity self, PyQuantity other):
    cdef PyQuantity nobj = PyQuantity(self)
    nobj._thisptr[0] += other._thisptr[0]

    return nobj

答案 1 :(得分:0)

接受答案的略微修改版本确实有效。 问题是+ =未实现(出于某种原因)所以     使用nobj._thisptr[0] = self._thisptr[0] + other._thisptr[0],但这会导致分段错误 - 显然,因为生成的Quantity对象不是堆分隔的。  最终的实施是:

    def __add__(PyQuantity self, PyQuantity other):
        cdef PyQuantity nobj = PyQuantity()
        nobj._thisptr = new Quantity(self._thisptr[0] +  other._thisptr[0])
        return nobj