gpt4 book ai didi

python - 如何在 Cython C++ 容器中存储 python 对象?

转载 作者:行者123 更新时间:2023-12-03 06:49:05 26 4
gpt4 key购买 nike

我想移植一个现有的 图书馆与 到 Python,使用 C++ 库 .在这种情况下,它是 adevs library .

问题是如何使用 Cython 在 C++ 容器中存储 Python 对象?我知道这是不知何故 discouraged ,对于引用计数的问题,但是可以这样做吗?如果可以,如何做?

我知道 Gauthier Boaglios' answersimilar 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 的回答所引用),那么您有多种选择。

  • 将值存储在 Cython/Python 中的某个位置,以在对象位于容器中时将引用计数保持在 1 以上。示例:
  • 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
  • 您可以使用 Python C-API 和 Wrapper 来手动递增和递减引用。用于引用计数的 Python C API 引用是 here . cython 包在 Cython 中自动向您提供此 API 作为 cython 声明 (.pxd) 文件,您可以将其导入(请参阅 here )。我可以在单独的 C++ 文件中添加引用计数功能,或者我可以根据 Interfacing with C guide 将此代码直接逐字添加到 Cython .像这样的事情是一个开始:
  • 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/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com