我想将带有c++的现有cython库移植到Python,使用templates的C ++库。在这种情况下,它是adevs library。
问题是我如何使用Cython将Python对象存储在C ++容器中?我知道这是discouraged,对于引用计数的问题,但是可以这样做,如果是的话,怎么做?
我知道Gauthier Boaglios' answer到similar question。但是,这并没有解决引用计数的问题,显然,我尝试了以下内容:
让我们说'cadevs.pxd'我有以下代码:
cdef extern from "adevs/adevs_digraph.h" namespace "adevs":
cdef cppclass PortValue[VALUE, PORT]:
PortValue() except +
PortValue(PORT port, const VALUE& value) except +
PORT port
VALUE value
在'adevs.pyx'中:
from cpython.ref cimport PyObject
cimport cadevs
ctypedef PyObject* PythonObject
cdef class PortValue:
cdef cadevs.PortValue[PythonObject, PythonObject]* _c_portvalue
def __cinit__(self, object port, object value):
self._c_portvalue = new cadevs.PortValue[PythonObject, PythonObject](
<PyObject *>port, <PyObject *>value
)
def __dealloc__(self):
del self._c_portvalue
property port:
def __get__(self):
return <object>self._c_portvalue.port
property value:
def __get__(self):
return <object>self._c_portvalue.value
然后我进行cythonize并编译
$ cython --cplus -3 adevs.pyx
$ g++ -shared -pthread -fPIC -fwrapv -O2 -Wall -I/usr/include/python3.4m -I../include -lpython3.4m -o adevs.so adevs.cpp
但是在python或ipython中运行
import adevs
pv = adevs.PortValue((1,2), 3)
pv.port
pv.port
崩溃了,因为对(1,2)元组的引用显然已经丢失了。
答案 0 :(得分:2)
您是对的,因为通过使用 Cython 将 Python 对象存储在 C++ 容器中,您将难以运行内存安全应用程序。如果您想在 Cython 中执行此操作,而不是 Pybind11(如 Mike MacNeil 的回答所引用),那么您有多种选择。
cdef class PortValue:
cdef cadevs.PortValue[PythonObject, PythonObject]* _c_portvalue
# Add fields to keep stored Python objects alive.
cdef object port_ref_holder
cdef object value_ref_holder
def __cinit__(self, object port, object value):
self._c_portvalue = new cadevs.PortValue[PythonObject, PythonObject](
<PyObject *>port, <PyObject *>value
)
# Assign objects here to keep them alive.
port_ref_holder = port
value_ref_holder = value
from cpython.ref cimport PyObject, Py_INCREF, Py_DECREF
cdef extern from *:
"""
class PyRef {
PyObject* obj;
public:
PyObject* get() {return obj;}
PyRef() {obj = NULL;}
PyRef(PyObject* set_obj) {
Py_XINCREF(set_obj);
obj = set_obj;}
~PyRef() {
Py_XDECREF(obj);obj = NULL;
}
PyRef(const PyRef& other) {
Py_XINCREF(other.obj);
obj = other.obj;
}
PyRef(PyRef&& other) {obj = other.obj; other.obj = NULL;}
PyRef& operator=(const PyRef& other) {
Py_XDECREF(obj);
Py_XINCREF(other.obj);
obj = other.obj;
return *this;
}
PyRef& operator=(PyRef&& other) {
Py_XDECREF(obj);
obj = other.obj;
other.obj = NULL;
return *this;
}
};
"""
cdef cppclass PyRef:
PyRef() except +
PyRef(PyObject* set_obj) except +
PyObject* get() except +
然后您使用“PyRef”类而不是 PythonObject 并使用其 get() 方法借用对存储的 Python 对象的引用。
答案 1 :(得分:1)
我不确定要绑定到Cython可能会很困难,我建议使用Pybind11,这相对(相对)容易为C ++编写python包装器(有关面向对象的代码,请参见this particular example)。 / p>