“无法将Python对象参数转换为类型'< typename>''”” -用Cython包装c ++类时出错 [英] "Cannot convert Python object argument to type '<typename>'" - error while wrapping c++-classes with Cython
问题描述
我正在尝试运行一个cython示例,它比许多教程(例如本指南)。
I'm trying to run a cython example which is a bit more complex than the one which can be found in many tutorials (e.g. this guide ).
这是一个最小的示例(请不要介意它没有太多功能)和重现我的问题的步骤:
Here are a minimal example (please don't mind it doesn't have much functionality) and steps to reproduce my problem:
有c ++类 Rectangle
和 Group2
(我将所有内容都放在.h文件中以使其更短):
There are c++-classesRectangle
and Group2
(I put here everything into the .h file to make it shorter):
// Rectangle.h
namespace shapes {
class Rectangle {
public:
Rectangle() {}
};
class Group2 {
public:
Group2(Rectangle rect0, Rectangle rect1) {}
};
}
然后我在同一个文件夹中创建一个 grp2.pyx 文件如上面的标头所示),使用 Rectangle
和 Group2
的包装器:
Then I create a grp2.pyx file (in the same folder as the above header), with wrappers for Rectangle
and Group2
:
# RECTANGLE
cdef extern from "Rectangle.h" namespace "shapes":
cdef cppclass Rectangle:
Rectangle() except +
cdef class PyRectangle:
cdef Rectangle c_rect
def __cinit__(self):
self.c_rect = Rectangle()
# GROUP2
cdef extern from "Rectangle.h" namespace "shapes":
cdef cppclass Group2:
Group2(Rectangle rect0, Rectangle rect1) except +
cdef class PyGroup2:
cdef Group2 c_group2
def __cinit__(self, Rectangle rect0, Rectangle rect1):
self.c_group2 = Group2(rect0, rect1)
扩展是通过我在命令行中调用的 setup.py
文件构建的( python setup.py build_ext -i
):
The extension is built via a setup.py
file that I call from command line (python setup.py build_ext -i
):
from distutils.core import setup, Extension
from Cython.Build import cythonize
setup(ext_modules = cythonize(Extension(
name="grp2", # the extension name
sources=["grp2.pyx"], # the Cython source
language="c++", # generate and compile C++ code
)))
PyGroup2的
: _cinint _
中的错误
At this point I have the error in the _cinint_
of PyGroup2
:
无法将Python对象参数转换为'Rectangle'类型
Cannot convert Python object argument to type 'Rectangle'
我想我的pyx文件中有一些错误,但是我不知道是什么。
I suppose there is some mistake in my pyx file, but I cannot tell what.
推荐答案
您应该使用<$ def
函数和 PyRectangle.c_rect
的签名中的c $ c> PyRectangle 将矩形传递给C ++函数。
You should use PyRectangle
in the signatures of def
-functions and PyRectangle.c_rect
when passing rectangles to C++-functions.
这意味着您的代码应为:
That means your code should be:
cdef class PyGroup2:
...
def __cinit__(self, PyRectangle rect0, PyRectangle rect1):
self.c_group2 = Group2(rect0.c_rect, rect1.c_rect)
请继续阅读,详细解释原因。
Read on for a more detailed explanation why.
所有传递给 def
-函数的参数都是Python对象(即(在Cython-parlance中类型为 object
的类型),所有这些函数都将从纯Python(仅知道Python对象)调用。
All arguments passed to def
-functions are Python-objects (i.e. of type object
in Cython-parlance), after all those functions will be called from pure Python, which only knows Python-objects.
但是,您可以添加一些语法糖,并在 def
函数的签名中使用 late-binding,而不是
However, you can add some syntactic sugar and use "late-binding" in the signature of a def
-function, for example, instead of
def do_something(n):
...
使用
def do_something(int n):
...
在后台,Cython会将这段代码转换为:
Under the hood, Cython will transform this code to something like:
def do_something(n_):
cdef int n = n_ # conversion to C-int
...
对于诸如 int
或 double
,因为Python-C-API中有这些转换的功能(即 PyLong_AsLong
, PyFloat_AsDouble
)。 Cython还会处理错误检查,因此您不应该手动进行这些转换。
This automatic conversion is possible for builtin-types like int
or double
, because there is functionality in Python-C-API for these conversions (i.e. PyLong_AsLong
, PyFloat_AsDouble
). Cython also handles the error checking, so you should not undertake these conversion manually.
但是,对于用户定义的类型/类,例如 Rectangle
-class这样的自动转换是不可能的-Cython只能自动转换为 cdef
-classes / extensions,即 PyRectangle
,因此在签名中应使用 PyRectangle
:
However, for user-defined types/classes like your Rectangle
-class such automatic conversion is not possible - Cython can only automatically convert to cdef
-classes/extensions, i.e. PyRectangle
, thus PyRectangle
should be used in the signature:
cdef class PyGroup2:
...
def __cinit__(self, PyRectangle rect0, PyRectangle rect1):
...
在Cython处理了从 object
到 PyRectangle
,从 PyRectangle
到 Rectangle
的最后一步必须通过使用 c_rect
-指针:
After Cython took care of conversion from object
to PyRectangle
, the last step from PyRectangle
to Rectangle
must be taken manually by utilizing the c_rect
- pointer:
...
def __cinit__(self, PyRectangle rect0, PyRectangle rect1):
self.c_group2 = Group2(rect0.c_rect, rect1.c_rect)
cpdef
-函数的规则相似,因为它们可以从纯Python调用。 早期绑定 仅适用于Cython可以使用的类型
The rules are similar for cpdef
-function, because they can be called from pure Python. The "early binding" works only for types which Cython can automatically coverted from/to Python objects.
毫无疑问,唯一可以在其签名中包含C ++类的函数是 cdef
功能。
Unsurprisingly, the only function which can habe C++-classes in their signatures are the cdef
-functions.
这篇关于“无法将Python对象参数转换为类型'< typename>''”” -用Cython包装c ++类时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!