23
cdef extern from "Foo.h":
    cdef cppclass Bar:
        pass

cdef class PyClass:
    cdef Bar *bar

    def __cinit__(self, Bar *b)
        bar = b

这总是会给我类似的东西:
Cannot convert Python object argument to type 'Bar *'

有没有办法做到这一点,或者我需要从一个Bar对象中提取所有内容,创建一个 Python 等价物,将其传入,然后在其中重建它PyClass

4

4 回答 4

10

我在尝试将带有结构的 C 代码包装为 python 类时遇到了这个问题。问题似乎是“特殊”功能,包括__init__并且__cinit__必须声明为def而不是cdef. 这意味着它们可以从普通的 python 中调用,所以类型参数被有效地忽略了,一切都被视为对象。

在 JF Sebastian 的回答中,修复不是包装 - double 是基本的数字类型,因此 C/C++ 类型和 Python 对象之间存在默认转换。Czarek 的回答基本上是正确的——你需要使用一个假的构造函数,使用一个全局函数。不能使用 @staticmethod 装饰器,因为它们不能应用于 cdef 函数。在提供的原始示例中,答案看起来更简单。

cdef extern from "Foo.h":
    cdef cppclass Bar:
        pass

cdef class PyClass:
    cdef Bar *bar

cdef PyClass_Init(Bar *b):
    result = PyClass()
    result.bar = b
    return result
于 2014-05-01T20:33:15.253 回答
8

Cython 0.21开始,可以使用装饰器声明cdef方法。@staticmethod这允许使用非 Python 参数的静态创建者方法:

cdef extern from "Foo.h":
    cdef cppclass Bar:
        pass

cdef class PyClass:
    cdef Bar *bar

    @staticmethod
    cdef create(Bar *bar):
        cdef PyClass pc = PyClass()
        pc.bar = bar
        return pc
于 2015-09-27T12:08:41.213 回答
5

为每个 cdef 类创建一个充当构造函数的全局 cdef 函数,CefResponse 是 C++ 对象,PyResponse 是 c++ 对象的 python 等效项:

cdef object CreatePyResponse(CefRefPtr[CefResponse] cefResponse):

    pyResponse = PyResponse()
    pyResponse.cefResponse = cefResponse
    return pyResponse

cdef class PyResponse:

    cdef CefRefPtr[CefResponse] cefResponse

    def GetStatus(self):

        return (<CefResponse*>(self.cefResponse.get())).GetStatus()

所以而不是resp = PyResponse(cppObject)call resp = CreatePyResponse(cppObject)

取自 CEF Python 的示例: https ://code.google.com/p/cefpython/source/browse/cefpython/response.pyx?r=0250b65e046a

于 2012-08-30T20:55:40.233 回答
1

Python 类接受 Python 参数。要传递 C++ 参数,您需要包装它:

# distutils: language = c++

cdef extern from "Foo.h" namespace "baz":
    cdef cppclass Bar:
         Bar(double d)
         double get()

cdef class PyBar: # wrap Bar class
    cdef Bar *thisptr
    def __cinit__(self, double d):
        self.thisptr = new Bar(d)
    def __dealloc__(self):
        del self.thisptr
    property d:
        def __get__(self):
            return self.thisptr.get()

PyBar实例可以用作 Cython 和纯 Python 中的任何其他 Python 对象:

class PyClass:
    def __init__(self, PyBar bar):
        self.bar = bar

print(PyClass(PyBar(1)).bar.d)
于 2012-09-01T22:45:41.447 回答