首页 > 解决方案 > 为什么我们几乎总是要在减少引用计数之前重新分配对象成员?

问题描述

我正在阅读本教程,以了解如何编写 C 扩展模块来定义新类型。在某些时候,给出了以下tp_init实现:

static int
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{
    static char *kwlist[] = {"first", "last", "number", NULL};
    PyObject *first = NULL, *last = NULL, *tmp;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
                                     &first, &last,
                                     &self->number))
        return -1;

    if (first) {
        tmp = self->first;
        Py_INCREF(first);
        self->first = first;
        Py_XDECREF(tmp);
    }
    if (last) {
        tmp = self->last;
        Py_INCREF(last);
        self->last = last;
        Py_XDECREF(tmp);
    }
    return 0;
}

我面临的麻烦是我看不出像这样分配第一个成员有什么害处:

if (first) {
    Py_XDECREF(self->first);
    Py_INCREF(first);
    self->first = first;
}

另一方面,上述教程警告我们不要使用它,因为:

我们的类型不限制第一个成员的类型,所以它可以是任何类型的对象。它可能有一个析构函数,导致代码被执行,试图访问第一个成员

它还继续说:

为了偏执并保护自己免受这种可能性的影响,我们几乎总是在减少引用计数之前重新分配成员

考虑到这些警告,我仍然看不出这两种方式之间有任何实际差异。first那么,为什么在减少旧的 PyObject 引用计数之前,我应该使用第一个将成员重新分配给新 PyObject 的方法?

标签: pythonpython-c-apipython-extensions

解决方案


推荐阅读