tp_clear,tp_dealloc和tp_free有什么区别?

wog*_*gio 3 c python python-extensions

我有一个用于模糊字符串搜索的自定义python模块,实现了Levenshtein距离计算,它包含一个称为levtree的python类型,它具有两个成员,该指针指向执行所有计算的wlevtree C类型(称为tree)的指针和指向的PyObject * python字符串的python列表,称为wordlist。这是我需要的:

-当我创建levtree的新实例时,我使用一个构造函数,该构造函数将字符串元组作为其唯一输入(并且该字典将在其中实例执行所有搜索),该构造函数将必须创建levtree的新实例。将wordlist添加到levtree的新实例中,然后将输入元组的内容复制到wordlist的新实例中。这是我的第一个代码段和第一个问题:

static int
wlevtree_python_init(wlevtree_wlevtree_obj *self, PyObject *args, PyObject *kwds)
{
    int numLines;       /* how many lines we passed for parsing */
    wchar_t** carg;        /* argument to pass to the C function*/
    unsigned i;

    PyObject * strObj;  /* one string in the list */
    PyObject* intuple;

    /* the O! parses for a Python object (listObj) checked
      to be of type PyList_Type */
    if (!(PyArg_ParseTuple(args, "O!", &PyTuple_Type, &intuple)))
    {
        return -1;
    }

    /* get the number of lines passed to us */
    numLines = PyTuple_Size(intuple);
    carg = malloc(sizeof(char*)*numLines);

    /* should raise an error here. */
    if (numLines < 0)
    {
        return -1; /* Not a list */
    }

    self->wordlist = PyList_New(numLines);
    Py_IncRef(self->wordlist);
    for(i=0; i<numLines; i++)
    {

        strObj = PyTuple_GetItem(intuple, i);
        //PyList_Append(self->wordlist, string);
        PyList_SetItem(self->wordlist, i, strObj);
        Py_IncRef(strObj);
    }

    /* iterate over items of the list, grabbing strings, and parsing
       for numbers */
    for (i=0; i<numLines; i++)
    {

        /* grab the string object from the next element of the list */
        strObj = PyList_GetItem(self->wordlist, i); /* Can't fail */

        /* make it a string */


        if(PyUnicode_Check(strObj))
        {
            carg[i] = PyUnicode_AsUnicode( strObj );
            if(PyErr_Occurred())
            {
                return -1;
            }
        }
        else
        {
            strObj = PyUnicode_FromEncodedObject(strObj,NULL,NULL);
            if(PyErr_Occurred())
            {
                return -1;
            }
            carg[i] = PyUnicode_AsUnicode( strObj );
        }
    }
    self->tree = (wlevtree*) malloc(sizeof(wlevtree));
    wlevtree_init(self->tree,carg,numLines);
    free(carg);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我是否必须调用Py_IncRef(self-> wordlist); 在self-> wordlist = PyList_New(numLines)之后; 还是多余的,因为引用已经在PyList_new中增加了?然后我对PyList_SetItem(self-> wordlist,i,strObj)也有同样的疑问;和Py_IncRef(strObj); ..

-销毁levtree实例时,我想调用C函数,以释放树占用的空间,销毁wordlist并减少对wordlist中包含的所有字符串的所有引用计数。.这是我的tp_dealloc:

static void
wlevtree_dealloc(wlevtree_wlevtree_obj* self)
{
    //wlevtree_clear(self);
    if(self->tree!=NULL)
    {
        wlevtree_free(self->tree);
    }
    free(self->tree);
    PyObject *tmp, *strObj;
    unsigned i;
    int size = PyList_Size(self->wordlist);
    for(i=0; i<size; i++)
    {
        strObj = PyList_GetItem(self->wordlist, i);
        Py_CLEAR(strObj);
    }
    Py_CLEAR(self->wordlist);
    Py_TYPE(self)->tp_free((PyObject *)self);
}
Run Code Online (Sandbox Code Playgroud)

使所有重新分配在这里工作是否正确?目前我没有tp_clear和tp_free,我需要它们吗?目前,我的代码适用于分配,而不适用于解除分配,因为即使我可以多次在同一个python变量上调用init,在每个python脚本的末尾(正确运行),我也会收到“分段错误”,这使我认为释放过程中出现了问题。

ste*_*rin 5

tp_clear仅当实现循环垃圾回收时才需要。似乎不需要这样做,因为您仅维护对Python unicode对象的引用。

tp_dealloc当对象的引用计数减少到零时,将调用。在这里销毁对象及其成员。然后,它应通过调用释放对象占用的内存tp_free。

tp_free是释放对象内存的位置。仅当您实现tp_alloc自己时才实现。

tp_dealloc和之间分开的原因tp_free是,如果您的类型是子类,则只有子类才知道如何分配内存以及如何正确释放内存。

如果您的类型是现有类型的子类,则tp_dealloc可能需要调用tp_dealloc派生类的,但这取决于案例的详细信息。

总而言之,似乎您正在正确地处理对象销毁(除了carg在退出该函数时出现错误时泄漏)。