“Cannot convert Python object argument to type ''” - error while wrapping c++-classes with Cython

前端 未结 1 1874
-上瘾入骨i
-上瘾入骨i 2021-01-23 13:49

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 d

1条回答
  •  一向
    一向 (楼主)
    2021-01-23 14:41

    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.


    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.

    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):
      ...
    

    use

    def do_something(int n):
      ...
    

    Under the hood, Cython will transform this code to something like:

    def do_something(n_):
       cdef int n = n_ # conversion to C-int
       ...
    

    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.

    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):
            ...
    

    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)
    

    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.

    Unsurprisingly, the only function which can habe C++-classes in their signatures are the cdef-functions.

    0 讨论(0)
提交回复
热议问题