Initializing Cython Objects with Existing C Objects

C ++ Model

Let's say I have the following C ++ data structures that I want to open Python.

#include <memory>
#include <vector>

struct mystruct
{
    int a, b, c, d, e, f, g, h, i, j, k, l, m;
};

typedef std::vector<std::shared_ptr<mystruct>> mystruct_list;

Boost Python

I can quite efficiently wrap them with boost :: python with the following code, easily allowing me to use the existing mystruct (copying shared_ptr) rather than recreate the existing object.

#include "mystruct.h"
#include <boost/python.hpp>

using namespace boost::python;


BOOST_PYTHON_MODULE(example)
{
    class_<mystruct, std::shared_ptr<mystruct>>("MyStruct", init<>())
        .def_readwrite("a", &mystruct::a);
        // add the rest of the member variables

    class_<mystruct_list>("MyStructList", init<>())
        .def("at", &mystruct_list::at, return_value_policy<copy_const_reference>());
        // add the rest of the member functions
}

Cython

In Cython, I have no idea how to extract an element from mystruct_list without copying the main data. I do not know how to initialize MyStructfrom an existing shared_ptr<mystruct>one without copying all the data in one of various forms.

from libcpp.memory cimport shared_ptr
from cython.operator cimport dereference


cdef extern from "mystruct.h" nogil:
    cdef cppclass mystruct:
        int a, b, c, d, e, f, g, h, i, j, k, l, m

    ctypedef vector[v] mystruct_list


cdef class MyStruct:
    cdef shared_ptr[mystruct] ptr

    def __cinit__(MyStruct self):
        self.ptr.reset(new mystruct)

    property a:
        def __get__(MyStruct self):
            return dereference(self.ptr).a

        def __set__(MyStruct self, int value):
            dereference(self.ptr).a = value


cdef class MyStructList:
    cdef mystruct_list c
    cdef mystruct_list.iterator it

    def __cinit__(MyStructList self):
        pass

    def __getitem__(MyStructList self, int index):
        # How do return MyStruct without copying the underlying `mystruct` 
        pass

I see many possible workarounds, and none of them are very satisfactory:

MyStruct, Cython shared_ptr. , - .

MyStruct value
value.ptr = self.c.at(index)
return value

MyStruct MyStruct. .

MyStruct value
dereference(value.ptr).a = dereference(self.c.at(index)).a
return value

init=True __cinit__, , C- ( init False). , API Python .

def __cinit__(MyStruct self, bint init=True):
    if init:
        self.ptr.reset(new mystruct)

__init__ , Python ( reset self.ptr), , __new__ Python.

Bottom-Line

Cython, , , boost:: python. pybind11 , , Cython.

, ​​ Cython? .

+6
1

Cython, factory Python . C/++ .

Cython:

<..>

cdef class MyStruct:
    cdef shared_ptr[mystruct] ptr

    def __cinit__(self):
        # Do not create new ref here, we will
        # pass one in from Cython code
        self.ptr = NULL

    def __dealloc__(self):
        # Do de-allocation here, important!
        if self.ptr is not NULL:
            <de-alloc>

    <rest per MyStruct code above>

cdef object PyStruct(shared_ptr[mystruct] MyStruct_ptr):
    """Python object factory class taking Cpp mystruct pointer
    as argument
    """
    # Create new MyStruct object. This does not create
    # new structure but does allocate a null pointer
    cdef MyStruct _mystruct = MyStruct()
    # Set pointer of cdef class to existing struct ptr
    _mystruct.ptr = MyStruct_ptr
    # Return the wrapped MyStruct object with MyStruct_ptr
    return _mystruct

def make_structure():
    """Function to create new Cpp mystruct and return
    python object representation of it
    """
    cdef MyStruct mypystruct = PyStruct(new mystruct)
    return mypystruct

, PyStruct Cpp.

mypystruct, python MyStruct, factory, Cpp . mypystruct def cython python, make_structure .

Python Cpp MyStruct, PyStruct

return PyStruct(my_cpp_struct_ptr)

Cython.

, def, Cpp MyStruct, Python, , , Cpp Cython GiL (, ).

. Cython Cython. . Python, C, GIL. Cpp, .

. Cython, / factory (Note that all constructor arguments will be passed as Python objects). Cython , / factory.

Cpp __new__ PyStruct, , , , factory ++ ( ).

factory , C/++ Python, . , , Python, C. Python ref , - . - null , , (, del).

, python, ++. , .

IMO C/++ API- Python C. , Python ( ), C/++ Python object.

. C, , C-, ++.

+3

All Articles