将C ++指针作为参数传递给Cython函数

时间:2012-08-30 19:53:17

标签: python cython

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 个答案:

答案 0 :(得分:9)

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

在J.F.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

答案 1 :(得分:6)

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

答案 2 :(得分:5)

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

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)致电resp = CreatePyResponse(cppObject)

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

答案 3 :(得分:2)

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)