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

Posted

技术标签:

【中文标题】在 cython 中返回 c++ 对象(最好不是指针)【英文标题】:Return c++ object (not a pointer preferably) in cython 【发布时间】:2016-09-02 06:24:37 【问题描述】:

我有两个类(让我们假设最简单的类,实现并不重要)。我的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++ 更改之后才能做到这一点,我想要最优雅的解决方案,如果可能的话。

【问题讨论】:

不确定你在问什么,但我认为你不能将“原始”C++ 对象返回给 Python;必须有某种包装。一旦您可以在 Python 代码中访问该对象,您打算如何处理它? @BrenBarn 我更正了 B 定义中的一个错误,所以 B 的方法 func 返回了 A 对象。当然,我希望在 Python 中能够编写像 a = b.func() 这样的东西,其中 b - 是 B 的包装器,a 是 A 的包装器。 您将需要使用复制或(更好的)移动构造函数来完成new A @DavidW 你能告诉我如何更改我的代码吗? 【参考方案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()))

【讨论】:

但我不需要做 deref(self._ths) 吗? 我不这么认为。我相信 Cython 可以根据需要选择是否使用 this.functhis->func 生成 c++ 代码。

以上是关于在 cython 中返回 c++ 对象(最好不是指针)的主要内容,如果未能解决你的问题,请参考以下文章

Cython - 将 C++ 函数返回的 C++(向量和非向量)对象暴露给 Python

从 C++ 函数 Cython 返回包含 PyObject 的复杂对象

如何使用 Cython 向 Python 公开返回 C++ 对象的函数?

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

Cython 中的 C++ 指针

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