convert python object to cython pointer

一个人想着一个人 提交于 2021-02-18 10:59:28

问题


I'm trying to expose c++ classes to python using cython. I wrote their definitions in *.pxd file and implemented a wrappers in *.pyx files. But I got stuck trying to pass to a function pointer to the extension type. Here is simplified example.

foo.pyx

from c_foo cimport cFoo
cdef class Foo:
    cdef cFoo* _impl

c_foo_holder.pxd

cdef extern from "FooHolder.h":
    cdef cppclass cFooHolder:
        cFooHolder(cFoo* foo)    

foo_holder.pyx

from c_foo_holder cimport cFooHolder
from c_foo cimport cFoo

cdef class FooHolder:
    cdef cFooHolder* _impl
    def __init__(self, foo):
        self._impl = new cFooHolder(<cFoo*>(foo._impl)) # error here    

But on the last line I get error "Python objects cannot be cast to pointers of primitive types". I also tried several other approaches, but nothing worked:

# error: 'Foo' is not a type identifier 
from foo import Foo
def __init__(self, Foo foo):
    self._impl = new cFooHolder(foo._impl)

# error: 'Foo' is not a type identifier 
def __init__(self, foo):
   self._impl = new cFooHolder(<Foo>(foo)._impl)

回答1:


I found the solution. You have to tell cython that foo._impl is really cFoo* instance. That can be achieved by providing Foo definition (e.g. in foo.pxd). Afterwards you are able to cast python object to Foo and cython will know that its _impl field has type cFoo*.

foo.pxd

from c_foo cimport cFoo
cdef class Foo:
    cdef cFoo* _impl

foo.pyx

from c_foo cimport cFoo
cdef class Foo:
    # methods implementation

c_foo_holder.pxd

cdef extern from "FooHolder.h":
    cdef cppclass cFooHolder:
        cFooHolder(cFoo* foo)    

foo_holder.pyx

from c_foo_holder cimport cFooHolder
from c_foo cimport cFoo
from foo cimport Foo

cdef class FooHolder:
    cdef cFooHolder* _impl
    def __init__(self, foo):
        self._impl = new cFooHolder((<Foo?>foo)._impl)  



回答2:


__init__ constructor can accept only pure python objects, there is also __cinit__ but it can accept only C primitive types.

When you pass Foo to __init__ it cannot see the _impl member, only members of python types can be seen.

The solution would be to pass cFoo* explicitly to an Init() method which emulates a constructor:

cdef class FooHolder:
    cdef cFooHolder* _impl
    cdef void Init(self, cFoo* foo_impl):
        self._impl = new cFooHolder(foo_impl)

Call it this way:

fooHolder = new FooHolder()
fooHolder.Init(foo._impl)


来源:https://stackoverflow.com/questions/13669961/convert-python-object-to-cython-pointer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!