Cython - 如何使用引用正确调用操作员

Posted

技术标签:

【中文标题】Cython - 如何使用引用正确调用操作员【英文标题】:Cython - how to properly call operator with references 【发布时间】:2016-06-11 16:12:12 【问题描述】:

我的 Cython 包装器中有以下代码到 C++ 代码:

# distutils: language = c++
# distutils: sources = symbolic.cpp
from libcpp.vector cimport vector
from libcpp.pair cimport pair
from libcpp.string cimport string
from libcpp cimport bool

cdef extern from "symbolic.h" namespace "metadiff::symbolic":
    cdef cppclass SymbolicMonomial:
        vector[pair[int, int]] powers
        long long coefficient;
        SymbolicMonomial()
        SymbolicMonomial(long)
        SymbolicMonomial(const SymbolicMonomial&)
        bool is_constant()
        long long int eval(vector[int]&)
        long long int eval()
        string to_string()
        string to_string_with_star() const

    cdef SymbolicMonomial mul_mm"operator*"(const SymbolicMonomial&, const SymbolicMonomial&)
    # SymbolicMonomial operator*(long long, const SymbolicMonomial&)
    # SymbolicMonomial operator*(const SymbolicMonomial&, long long)


cdef class SymMonomial:
    cdef SymbolicMonomial* thisptr      # hold a C++ instance which we're wrapping
    def __cinit__(self):
        self.thisptr = new SymbolicMonomial()
    def __cinit__(self, int value):
        self.thisptr = new SymbolicMonomial(value)
    def __dealloc__(self):
        del self.thisptr
    def is_constant(self):
        return self.thisptr.is_constant()
    def eval(self):
        return self.thisptr.eval()
    def __str__(self):
        return self.to_string_with_star()
    def to_string(self):
        return self.thisptr.to_string().decode('UTF-8')
    def to_string_with_star(self):
        return self.thisptr.to_string_with_star().decode('UTF-8')
    def __mul__(self, other):
        return mul_mm(self.thisptr, other)
def variable(variable_id):
    monomial = SymMonomial()
    monomial.thisptr.powers.push_back((variable_id, 1))
    return monomial

但是,我从来没有弄清楚如何正确调用mul_mm 方法。它一直说Cannot convert 'SymbolicMonomial' to Python object,反之亦然。问题是我需要能够以这种方式将两个 SymMonomials 相乘。但是由于某种原因,我无法掌握如何正确执行此操作的窍门。有什么建议吗?

【问题讨论】:

【参考方案1】:

你有很多问题:

    您不能将 C++ 对象直接返回给 Python - 您需要返回您的包装器类型(分配给包装器的 thisptr

    您不能保证 selfother 在调用函数时是正确的类型(请参阅 http://docs.cython.org/src/userguide/special_methods.html#arithmetic-methods 中关于如何使用操作数调用方法的注释任一顺序)。要使用 Cython 类的 C/C++ 成员,您需要确保 Cython 知道该对象确实属于该类。我建议使用<Classname?> 样式转换(注意问号),如果不匹配则会引发异常。

    您还需要从 other 获取 thisptr,而不是仅仅将 Python 包装类传递给您的 C++ 函数。

以下应该可以工作。

def __mul__(self,other):
    cdef SymMonomial tmp = SymMonomial()
    cdef SymMonomial self2, other2
    try:
        self2 = <SymMonomial?>self
        other2 = <SymMonomial?>other
    except TypeError:
        return NotImplemented # this is what Python expects for operators
                      # that don't know what to do
    tmp.thisptr[0] = mul_mm(self2.thisptr[0],other2.thisptr[0])
    return tmp

【讨论】:

嘿,我认为你的建议解决了一些问题。但是,由于 mul_mm 重命名,我仍然得到这个:/home/alex/work/c/swig_test/symbolic.h:298: multiple definition of `metadiff::symbolic::operator*(metadiff::symbolic::SymbolicMonomial const&amp;, metadiff::symbolic::SymbolicMonomial const&amp;)' 。你知道为什么会这样吗?我的头文件中有保护,但由于某种原因,它似乎包含了两次? 其实我发现了问题。

以上是关于Cython - 如何使用引用正确调用操作员的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Cython 中调用多线程 C 函数?

使用 Cython 时如何将一个 C++ 类(引用)传递给另一个?

如何通过cython接口返回对象引用的c ++函数

如何在 cython 中调用此函数?

如何在 Cython 中正确管理 C++ 对象的生命周期?

如何从另一个包装的对象返回 Cython 中的包装 C++ 对象?