如何清除包含对象的 PyList 对象?
How to clear a PyList object that contains objects?
我正在尝试清除使用 ctypes 传递给 C 函数的 Python 列表。我在 this link 找到的调用有时似乎有效,但是当我传入的列表包含其他列表或 classes 作为元素时,我得到一个段错误。
我有一个文件 foo.py 如下所示:
import ctypes
_libpractice=ctypes.CDLL('./_practice.so', mode=ctypes.RTLD_GLOBAL)
_libpractice.update.argtypes = [ctypes.py_object]
_libpractice.update.restype = ctypes.py_object
def c_update(my_list):
return _libpractice.update(my_list)
和一个如下所示的文件 practice.c:
#include <Python.h>
#include <stdio.h>
PyObject* update(PyObject* list){
Py_INCREF(list);
Py_ssize_t len = PySequence_Length(list);
PySequence_DelSlice(list, 0, len);
return list;
}
这是一个它可以正确处理各种原始数据类型的示例。
>>> import foo
>>> a = [1,2,3,4,5.5,'a',6]
>>> foo.c_update(a)
[]
>>>
这是段错误的示例:
>>> b = [1,2,3,[],5]
>>> foo.c_update(b)
Segmentation fault (core dumped)
我找到了解决这个问题的方法,方法是对列表中的每个项目调用 PySequence_GetItem()
,然后像这样调用 PySequence_DelSlice()
:
PyObject* update(PyObject* list){
Py_INCREF(list);
Py_ssize_t len = PySequence_Length(list);
for(Py_ssize_t i = 0; i<len; i++){
PyObject* item = PySequence_GetItem(list,i);
}
PySequence_DelSlice(list, 0, len);
return list;
}
但是,如果我将 class 作为列表的元素传递,则在从列表中删除后不会调用析构函数。
>>> import foo
>>> class Sample:
... def __del__(self):
... print('del called')
...
>>> a = Sample()
>>> a = 3
del called
>>> b = Sample()
>>> my_list = [1,b,3,[]]
>>> foo.c_update(my_list)
[]
>>>
如何清除传入的列表,同时确保正确处理引用计数?
我不知道这是否是段错误的直接原因,但您不能在作为 CDLL 加载的库中使用 Python API。你必须使用 PyDLL。使用 CDLL,Python 将在从该库调用函数之前释放 GIL,而您需要 GIL。
我正在尝试清除使用 ctypes 传递给 C 函数的 Python 列表。我在 this link 找到的调用有时似乎有效,但是当我传入的列表包含其他列表或 classes 作为元素时,我得到一个段错误。
我有一个文件 foo.py 如下所示:
import ctypes
_libpractice=ctypes.CDLL('./_practice.so', mode=ctypes.RTLD_GLOBAL)
_libpractice.update.argtypes = [ctypes.py_object]
_libpractice.update.restype = ctypes.py_object
def c_update(my_list):
return _libpractice.update(my_list)
和一个如下所示的文件 practice.c:
#include <Python.h>
#include <stdio.h>
PyObject* update(PyObject* list){
Py_INCREF(list);
Py_ssize_t len = PySequence_Length(list);
PySequence_DelSlice(list, 0, len);
return list;
}
这是一个它可以正确处理各种原始数据类型的示例。
>>> import foo
>>> a = [1,2,3,4,5.5,'a',6]
>>> foo.c_update(a)
[]
>>>
这是段错误的示例:
>>> b = [1,2,3,[],5]
>>> foo.c_update(b)
Segmentation fault (core dumped)
我找到了解决这个问题的方法,方法是对列表中的每个项目调用 PySequence_GetItem()
,然后像这样调用 PySequence_DelSlice()
:
PyObject* update(PyObject* list){
Py_INCREF(list);
Py_ssize_t len = PySequence_Length(list);
for(Py_ssize_t i = 0; i<len; i++){
PyObject* item = PySequence_GetItem(list,i);
}
PySequence_DelSlice(list, 0, len);
return list;
}
但是,如果我将 class 作为列表的元素传递,则在从列表中删除后不会调用析构函数。
>>> import foo
>>> class Sample:
... def __del__(self):
... print('del called')
...
>>> a = Sample()
>>> a = 3
del called
>>> b = Sample()
>>> my_list = [1,b,3,[]]
>>> foo.c_update(my_list)
[]
>>>
如何清除传入的列表,同时确保正确处理引用计数?
我不知道这是否是段错误的直接原因,但您不能在作为 CDLL 加载的库中使用 Python API。你必须使用 PyDLL。使用 CDLL,Python 将在从该库调用函数之前释放 GIL,而您需要 GIL。