当函数窃取引用时,Cython 函数声明



有一些Python C-API函数会窃取一个传递的参数的引用,例如PyList_SetItem,而其他函数则增加参数的引用计数,例如PyList_Append

我可以告诉Cython参考资料会被盗吗?还是我需要手动使用Py_INCREF

from cpython.object cimport PyObject
from cpython.ref cimport Py_INCREF
cdef extern from "Python.h":
    void PyList_SetItem(object list, Py_ssize_t i, object o)
cpdef void func(list lst, object item):
    Py_INCREF(item)
    PyList_SetItem(lst, 0, item)

我知道如果一个函数返回借用的引用,则可以更改返回类型(PyObject *借用的引用,object非借用的引用):

from cpython.object cimport PyObject
from cpython.ref cimport Py_INCREF
cdef extern from "Python.h":
    PyObject* PyList_GetItem(object list, Py_ssize_t index)
    object PyObject_GetItem(object o, object key)

但这似乎不适用于被盗的参考资料(或者我的想法是错误的?

from cpython.object cimport PyObject
cdef extern from "Python.h":
    void PyList_SetItem(object list, Py_ssize_t i, PyObject *o)
cpdef void func(list lst, object item):
    PyList_SetItem(lst, 0, <PyObject*>item)

在 Cython 中没有自动处理"窃取"的方法(还?),所以人们必须回到有点尴尬的手动处理(如问题本身所指出的):

%%cython
from cpython.ref cimport Py_INCREF
from cpython.list cimport PyList_SetItem
def replace(list lst, object item):
    Py_INCREF(item) # prepare for stealing 
    PyList_SetItem(lst, 0, item)

行为符合预期:

import sys
a, b= float(), float()
lst = [a]
print(sys.getrefcount(a), sys.getrefcount(b))
# refcount(a)=3 and refcount(b)=2
replace(lst, b)
print(sys.getrefcount(a), sys.getrefcount(b))
# refcount(a)=3 and refcount(b)=2

最新更新