简体   繁体   中英

Passing pointer to constructor in Cython

This might be a stupid question, but how can I pass a "raw" pointer to a constructor of a Cython object? The problem appears to be that __init__ and __cinit__ cannot be cdef or cpdef but must be def .

What is the best practice workaround here? Create a wrapper class for the allocated memory?

The following works

# ex1.pyx
from libc.stdlib cimport malloc, free

cdef class Klass1:
    cdef void * ptr

    cdef void _init(self, void * ptr):
        self.ptr = ptr

    def bar(self):
        free(self.ptr)

def foo():
    o = Klass1()
    o._init(malloc(100))
    o.bar()

While the following does not:

# ex2.pyx
from libc.stdlib cimport malloc, free

cdef class Klass2:
    cdef void * ptr

    def __init__(self, ptr):  # __init__ cannot be cdef
        self.ptr = ptr

    def bar(self):
        free(self.ptr)

def foo():
    o = Klass2(malloc(100))
    o.bar()

The following setup.py can be used for building:

from distutils.core import setup
from Cython.Build import cythonize

setup(name='ex1', ext_modules=cythonize('ex1.pyx')) # or ex2.pyx

There's a number of options, depending on the use-case. __init__ / __cinit__ are designed to construct your classes from Python (where pointers are meaningless) hence the restriction.

In your example (which I suspect is simplified) you could just put the malloc call inside the constructor:

# rest of class definition goes here
def __init__(self,size):
  self.ptr = malloc(size)
# and more code follows

Another possibility would be to use a static method instead of __init__ . (This is actually suggested in the Cython documentation for this purpose: http://docs.cython.org/src/userguide/extension_types.html#c-methods ). I've just copied the example from the documentation:

cdef class OwnedPointer:
    cdef void* ptr

    cdef __dealloc__(self):
        if ptr != NULL:
            free(ptr)

    @staticmethod
    cdef create(void* ptr):
        p = OwnedPointer()
        p.ptr = ptr
        return ptr

A third option is to use wrapper classes as you suggest - the issue with this is that you still have to construct them somehow (and thus you're back to the two techniques mentioned). This would probably be most appropriate where the pointer is actually to a known C/C++ datatype, which you are able to get from another function or construct easily yourself, and it would be useful to be able the handle these from pure Python code. A good outline is at http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#create-cython-wrapper-class - depending on what you wanted to do you might only chose to create a constructor and destructor and not to map the member functions (if there are any).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM