我在 Cython 中有一个链表的小型实现,我希望向列表添加一个值。
出于某种原因,当我尝试
Py_INCREF
(以确保在每个节点中保留强引用)时,Cython 不接受指向 Python 对象的指针,而只接受对象本身:
ctypedef struct Node:
PyObject* group
PyObject* value # (group, value)
Node* next
cdef bint _put(object group, object value) except 1:
cdef:
Node* node = <Node*>PyMem_Malloc(sizeof(Node))
PyObject* _group = <PyObject*> group
PyObject* _value = <PyObject*> value
if not node:
raise MemoryError("Failed to allocate memory for new node")
node.group = _group
Py_INCREF(node.group) # Cannot convert 'PyObject *' to Python object
Py_INCREF(_group) # Cannot convert 'PyObject *' to Python object
Py_INCREF(<PyObject*> group) # Cannot convert 'PyObject *' to Python object
Py_INCREF(group) # Works
据说,
Py_INCREF
应该与 PyObject*
一起使用。
在网上查找和chatgpt都直接建议:
Cython 中的与Py_INCREF
一起使用,它是指向 Python 对象,而不是 Python 级别的对象。因此,你应该通过PyObject*
(指针)到PyObject*
。Py_INCREF
代码看起来很简单,我不确定为什么它不起作用。
想必您是从
cpython.ref
导入的?
这很大程度上只是因为它的定义方式:
void Py_INCREF(object o)
Cython 一般使用的约定是:
object
如果不能为NULLPyObject*
如果可以为NULL。由于
INCREF
不接受 NULL 参数,因此它是 object
。 XINCREF
接受 NULL 参数的是 PyObject*
。
即使您不喜欢该约定,现阶段也很难更改,因为有大量代码使用当前定义。
您有两个选择:
投射到对象:
Py_INCREF(<object>node.group)
编写适合您想要的自己的定义(Cython 公开的 C API 定义不会做任何您自己做不到的事情):
cdef extern from "Python.h":
void Py_INCREF(PyObject* o)