在cython中返回c ++对象(最好不是指针)

时间:2016-09-02 06:24:38

标签: python c++ cython

我有两个课程(让我们假设最简单的课程,实施并不重要)。我的defs.pxd文件(使用cython defs)看起来像这样:

cdef extern from "A.hpp":
  cdef cppclass A:
    A() except +

cdef extern from "B.hpp":
  cdef cppclass B:
    B() except +
    A func ()

我的pyx文件(使用python defs)如下所示:

from cython.operator cimport dereference as deref
from libcpp.memory cimport shared_ptr

cimport defs

cdef class A:
    cdef shared_ptr[cquacker_defs.A] _this

    @staticmethod
    cdef inline A _from_this(shared_ptr[cquacker_defs.A] _this):
        cdef A result = A.__new__(A)
        result._this = _this
        return result

    def __init__(self):
        self._this.reset(new cquacker_defs.A())

cdef class B:
    cdef shared_ptr[cquacker_defs.B] _this

    @staticmethod
    cdef inline B _from_this(shared_ptr[cquacker_defs.B] _this):
        cdef B result = B.__new__(B)
        result._this = _this
        return result

    def __init__(self):
        self._this.reset(new cquacker_defs.B())

    def func(self):
      return deref(self._this).func()

问题是我无法从Python返回非python对象。实际上,我不想改变我的c ++代码来返回指针而不是新对象(因为有很多这样的函数)。现在它给了我错误:

Cannot convert 'B' to Python object

如何从python中的另一个方法返回一个包含内部c ++对象的python对象?如果我只能在一些c ++更改后才这样做,我想要最优雅的解决方案,如果可能的话。

1 个答案:

答案 0 :(得分:1)

您的问题是您的包装类需要一个指针(指向new分配的对象),但您的函数会在堆栈上返回一个C ++对象。要解决此问题,您必须从堆栈中复制或移动对象。

首先确保您的C ++类A具有工作副本或移动构造函数。如果你的c ++类包含大型成员,那么移动构造函数会更好。包裹这是Cython就像这样:

cdef extern from "A.hpp":
  cdef cppclass A:
    A() except +
    A(const A&) except +
    # or A(A&&) except +

(不要告诉Cython关于复制构造函数和移动构造函数 - 它会让人感到困惑!C ++在编译时会找到正确的编译器。)

然后,在func中使用带有new的复制/移动构造函数传递给你的python包装器:

def func(self):
      return A._from_this(new cquacker_defs.A(self._this.func()))