如何从另一个包装的对象返回 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
,然后使用B
s 移动(或复制)构造函数来创建一个B*
。
如果可以的话,你最好使用移动构造函数而不是复制构造函数,但是你不需要告诉 Cython 任何一个(C++ 会自动选择正确的)。
【讨论】:
以上是关于如何从另一个包装的对象返回 Cython 中的包装 C++ 对象?的主要内容,如果未能解决你的问题,请参考以下文章
包装采用 char** [in/out] 的 C 函数调用,以在 cython 中返回 python 列表
如何在 python 包装中使用 unicode 字符串用于带有 cython 的 c++ 类?