Cython 中的 Py_INCREF 接受 Python 对象但不接受指针

问题描述 投票:0回答:1

我在 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
PyObject*
一起使用,它是指向 Python 对象,而不是 Python 级别的对象。因此,你应该通过
PyObject*
(指针)到
Py_INCREF

代码看起来很简单,我不确定为什么它不起作用。

python cython
1个回答
0
投票

想必您是从

cpython.ref
导入的?

这很大程度上只是因为它的定义方式

    void Py_INCREF(object o)

Cython 一般使用的约定是:

  • object
    如果不能为NULL
  • PyObject*
    如果可以为NULL。

由于

INCREF
不接受 NULL 参数,因此它是
object
XINCREF
接受 NULL 参数的是
PyObject*

即使您不喜欢该约定,现阶段也很难更改,因为有大量代码使用当前定义。


您有两个选择:

  1. 投射到对象:

    Py_INCREF(<object>node.group)
    
  2. 编写适合您想要的自己的定义(Cython 公开的 C API 定义不会做任何您自己做不到的事情):

    cdef extern from "Python.h":
       void Py_INCREF(PyObject* o)
    
© www.soinside.com 2019 - 2024. All rights reserved.