有一些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