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

Posted

技术标签:

【中文标题】如何从另一个包装的对象返回 Cython 中的包装 C++ 对象?【英文标题】:How do I return wrapped C++ Objects in Cython from another wrapped Object? 【发布时间】:2016-11-11 16:29:28 【问题描述】:

我一直在用 Cython 包装 C++ 类。现在我有以下问题:A 类有一个方法 foo(),它返回 B 类的一个实例。两者都是 C++ 类。两者都被包裹在 Cython 中到类 PyA 和 PyB。我想以某种方式使用户可以访问方法 foo(),即用户调用 PyA_object.foo() 并获取 PyB_object。如何实现该方法?

cimport cppClassA

cdef class A:
    cdef cppClassA.A *ptr
    ...
def foo():
    return self.ptr.foo()

这样我返回了直接的 C++ Class B,但我想返回一个 PyB。因此我需要创建一个 PyB 对象,但是如何构造 PyB 的 cinit() 方法呢?如何将 self.ptr.foo() 返回的对象提供给新的 PyB 对象并返回它?

【问题讨论】:

【参考方案1】:

您的问题并不完全清楚 foo 是通过指针还是值返回(即它是否具有签名 B* foo()B foo())。你必须做什么取决于这一点 - 我已经展示了两者。

我认为您遇到的问题是PyB__init____cinit__ 方法只能将Python 对象作为参数,因此您无法通过C++ @987654327 @object in。解决方法是创建一个PyB,它要么是空的,要么具有默认的C++ 对象为ptr,然后替换它。

C++ 代码的包装看起来像这样

cdef extern from "somefile.hpp":
    cdef cppclass A:
        B foo1()
        B* foo2()

    cdef cppclass B:
        # only need to provide these for foo1_alternative
        B()
        B(const B&)

请注意,我提供了两个版本的foo - foo1 按值返回,foo2 返回指针。

Python B 持有者 (PyB) 看起来像

cdef class PyB:
    cdef B* ptr

    def __cinit__(self,make_ptr=True):
        if make_ptr:
            self.ptr = new B()
        else:
            self.ptr = NULL

    def __dealloc__(self):
        del self.ptr

我提供了一个可选的 make_ptr 参数,您可以将其设置为 False 以避免将 self.ptr 设置为任何值。

然后是 Python A 持有者 (PyA)

cdef class PyA:
    cdef A* ptr

    # code goes here

    def foo1(self):
        cdef PyB val = PyB()
        val.ptr[0] = self.ptr.foo1() # use move (or copy) assignment operator

    def foo1_alternative(self):
        cdef PyB val = PyB(make_ptr=False)
        val.ptr = new B(self.ptr.foo1()) # use move (or copy) constructor

    def foo2(self):
        cdef PyB val = PyB(make_ptr=False)
        val.ptr = self.ptr.foo2()

对于返回指针的foo2,您只需创建一个空的PyB 并将Foo* 赋值给self.ptr。对于foo1,您有两个选择,其中之一是创建一个PyB,然后使用移动(或复制)赋值运算符复制数据。第二个选项涉及创建一个空的PyB,然后使用Bs 移动(或复制)构造函数来创建一个B*

如果可以的话,你最好使用移动构造函数而不是复制构造函数,但是你不需要告诉 Cython 任何一个(C++ 会自动选择正确的)。

【讨论】:

以上是关于如何从另一个包装的对象返回 Cython 中的包装 C++ 对象?的主要内容,如果未能解决你的问题,请参考以下文章

包装采用 char** [in/out] 的 C 函数调用,以在 cython 中返回 python 列表

如何在 cython 模块中使用外部包装类?

如何在 Cython 中返回新的 C++ 对象?

如何在 python 包装中使用 unicode 字符串用于带有 cython 的 c++ 类?

用函数指针包装 C++ 代码作为 cython 中的模板参数

如何用 Cython 包装 C++ 类?