如何在 Cython 中返回新的 C++ 对象?
Posted
技术标签:
【中文标题】如何在 Cython 中返回新的 C++ 对象?【英文标题】:How to return new C++ objects in Cython? 【发布时间】:2013-06-02 12:09:03 【问题描述】:我怀疑这个问题有一个简单的答案,但我需要一些帮助才能开始使用 Cython。我有一个现有的 C++ 代码库,我想通过 Cython 向 Python 公开。对于我要公开的每个类,我创建了一个 Cython cppclass _ClassName
和 Python 包装类 ClassName
。
一个小例子:
Object.h
CythonMinimal.pyx
setup.py
Object.h
的内容:
class Object
public:
Object clone()
Object o;
return o;
;
CythonMinimal.pyx
的内容:
cdef extern from "Object.h":
cdef cppclass _Object "Object":
_Object() except +
_Object clone()
cdef class Object:
cdef _Object *thisptr
def __cinit__(self):
self.thisptr = new _Object()
def __dealloc__(self):
del self.thisptr
def clone(self):
return self.thisptr.clone()
setup.py
的内容
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext
import os
os.environ["CC"] = "g++-4.7"
os.environ["CXX"] = "g++-4.7"
modules = [Extension("CythonMinimal",
["CythonMinimal.pyx"],
language = "c++",
extra_compile_args=["-std=c++11"],
extra_link_args=["-std=c++11"])]
for e in modules:
e.cython_directives = "embedsignature" : True
setup(name="CythonMinimal",
cmdclass="build_ext": build_ext,
ext_modules=modules)
这是我编译时遇到的错误:
cls ~/workspace/CythonMinimal $ python3 setup.py build
running build
running build_ext
cythoning CythonMinimal.pyx to CythonMinimal.cpp
Error compiling Cython file:
------------------------------------------------------------
...
def __dealloc__(self):
del self.thisptr
def clone(self):
return self.thisptr.clone()
^
------------------------------------------------------------
CythonMinimal.pyx:18:27: Cannot convert '_Object' to Python object
building 'CythonMinimal' extension
creating build
creating build/temp.macosx-10.8-x86_64-3.3
g++-4.7 -Wno-unused-result -fno-common -dynamic -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -I/usr/local/include -I/usr/local/opt/sqlite/include -I/usr/local/Cellar/python3/3.3.0/Frameworks/Python.framework/Versions/3.3/include/python3.3m -c CythonMinimal.cpp -o build/temp.macosx-10.8-x86_64-3.3/CythonMinimal.o -std=c++11
cc1plus: warning: command line option '-Wstrict-prototypes' is valid for C/ObjC but not for C++ [enabled by default]
CythonMinimal.cpp:1:2: error: #error Do not use this file, it is the result of a failed Cython compilation.
error: command 'g++-4.7' failed with exit status 1
我假设_Object.clone
需要返回一个_Object
(cppclass 类型),但Objet.clone
应该返回一个Object
(Python 类型)。但是怎么做呢?
【问题讨论】:
您能否将其简化为一个严格最小的示例(例如,不超过一个 .h 头文件),并在此处发布所有文件(C++ 代码、.h 标头、setup.py、cython 包装器、蟒蛇应用程序)?由于不存在有关 Cython/C++ 绑定的全面文档,因此我们中的许多人在这里(或在 cython-devel@python.org 上?)协作以运行一个最小的示例会很有帮助。 我将尝试构建一个最小的示例。但是我认为这是一个相当普遍的初学者问题并且对于具有 Cython+C++ 经验的人来说解决方案应该是显而易见的,我错了吗? 经验丰富的 Cython/C++ 开发人员并不多 - 除非改进文档,否则他们不太可能变得更多。就我个人而言,学习 Cython/C++ 是我的首要任务;但在第一次尝试以未解决的问题结束后,我推迟了进一步的努力。因此,我想用你的例子重新尝试...... @JoachimWuttke 我发布了一个完整的最小示例。问题依旧。 cls,您使用的是哪个 Cython 版本?您的代码基于哪篇文档? 【参考方案1】:您正在一个 Python 函数中返回一个 C++ 对象,该函数只允许返回 Python 对象:
def clone(self):
return self.thisptr.clone()
把它变成这样:
cdef _Object clone(self) except *:
return self.thisptr.clone()
但这取决于你想要做什么,你可能想要返回 Object 而不是 _Object,所以我会这样修改它:
cdef class Object:
cdef _Object thisobj
cdef _Object *thisptr
def __cinit__(self, Object obj=None):
if obj:
self.thisobj = obj.thisobj.clone()
self.thisptr = &self.thisobj
def __dealloc__(self):
pass
def clone(self):
return Object(self)
【讨论】:
正确,我想返回Object
,而不是_Object
我认为这可以作为一个通用解决方案,不仅仅是在这个示例的特殊情况下存在克隆方法:def __cinit__(self, _Object obj=None): ...
但__cinit__
不接受_Object
,因为它不能将其转换为 Python 对象。
@cls 不能将 C++ 对象传递给构造函数,这是不允许的,但是可以在构造对象后设置属性。 obj = Object(); obj.thisptr = myCppObj;
。您可以为此创建包装函数:cdef CreateObject(_Object _obj): obj = Object(); obj.thisptr = _obj; return obj;
.
要使@Czarek 的解决方案有效,您需要修改C++ clone 方法以返回一个指针:class Object public: Object* clone() Object *p; p = 新对象();返回 p; ;
在我接受之前要求答案中的代码编译是否太过分了?以上是关于如何在 Cython 中返回新的 C++ 对象?的主要内容,如果未能解决你的问题,请参考以下文章
如何从另一个包装的对象返回 Cython 中的包装 C++ 对象?