我想移植一个现有的 c++图书馆与 cython到 Python,使用 C++ 库 templates .在这种情况下,它是 adevs library .
问题是如何使用 Cython 在 C++ 容器中存储 Python 对象?我知道这是不知何故 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
在“advs.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) 元组的引用丢失,Python 崩溃。
最佳答案
您是对的,通过使用 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 对象的引用。
关于python - 如何在 Cython C++ 容器中存储 python 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26937213/