簡體   English   中英

“無法將 Python 對象參數轉換為類型 &#39;<typename> &#39;&quot; - 用 Cython 包裝 c++ 類時出錯

[英]"Cannot convert Python object argument to type '<typename>'" - error while wrapping c++-classes with Cython

我正在嘗試運行一個 cython 示例,該示例比許多教程(例如本指南)中的示例要復雜一些。

這是一個最小的示例(請不要介意它沒有太多功能)和重現我的問題的步驟:

有 c++-classes RectangleGroup2 (我把所有東西都放到了 .h 文件中以使其更短):

// Rectangle.h
namespace shapes { 
    class Rectangle {
        public:
            Rectangle() {}
    };

    class Group2 {
    public:
        Group2(Rectangle rect0, Rectangle rect1) {}
    };
}

然后我創建了一個grp2.pyx文件(在與上述標題相同的文件夾中),其中包含RectangleGroup2包裝器:

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

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

此時我在_cinint_PyGroup2出現錯誤:

無法將 Python 對象參數轉換為“矩形”類型

我想我的 pyx 文件中有一些錯誤,但我不知道是什么。

將矩形傳遞給 C++ 函數時,您應該在def PyRectangle.c_rectPyRectangle.c_rect的簽名中使用PyRectangle

這意味着您的代碼應該是:

cdef class PyGroup2:
    ...
    def __cinit__(self, PyRectangle rect0, PyRectangle rect1):
        self.c_group2 = Group2(rect0.c_rect, rect1.c_rect)

請繼續閱讀以獲取更詳細的解釋。


傳遞給所有的參數def -functions是Python的對象(即類型的object在用Cython-說法),畢竟這些功能將來自純Python,只知道Python的對象調用。

但是,您可以添加一些語法糖並在def函數的簽名中使用“后期綁定”,例如,而不是

def do_something(n):
  ...

def do_something(int n):
  ...

在幕后,Cython 會將此代碼轉換為類似以下內容:

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

這種自動轉換對於像intdouble這樣的內置類型是可能的,因為 Python-C-API 中有這些轉換的功能(即PyLong_AsLongPyFloat_AsDouble )。 Cython 還處理錯誤檢查,因此您不應手動進行這些轉換。

但是,對於像您的Rectangle -class 這樣的用戶定義類型/類,這種自動轉換是不可能的 - Cython 只能自動轉換為cdef -classes/extensions,即PyRectangle ,因此PyRectangle應該在簽名中使用:

cdef class PyGroup2:
    ...
    def __cinit__(self, PyRectangle rect0, PyRectangle rect1):
        ...

在 Cython 處理了從objectPyRectangle的轉換PyRectangle ,從PyRectangleRectangle的最后一步必須通過使用c_rect - 指針手動c_rect

...
def __cinit__(self, PyRectangle rect0, PyRectangle rect1):
    self.c_group2 = Group2(rect0.c_rect, rect1.c_rect)

cpdef的規則類似,因為它們可以從純 Python 中調用。 “早期綁定”僅適用於 Cython 可以自動從/向 Python 對象轉換的類型。

不出所料,唯一可以在其簽名中包含 C++ 類的函數是cdef函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM