“无法将Python对象参数转换为类型'< typename>''”” -用Cython包装c ++类时出错 [英] "Cannot convert Python object argument to type '<typename>'" - error while wrapping c++-classes with Cython

查看:128
本文介绍了“无法将Python对象参数转换为类型'< typename>''”” -用Cython包装c ++类时出错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试运行一个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对象参数转换为类型'&lt; typename&gt;''”” -用Cython包装c ++类时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆