Python拓展开发

发表时间: 2020-05-24 22:14:19 作者: 何景松 7 299

    前些日子写了一个序列化工具,想着为这个工具写一个python拓展。写这篇文章就是为了记录一下写python拓展时遇到的坑。

    python版本:Python-3.7.5

    1、未减少引用计数问题

    static void getData(const void *pyObject, sg_UserData *ud) { PyObject* object = (PyObject*)pyObject; PyObject *key = NULL; PyObject *value = NULL; key = PyUnicode_FromString(fieldName); value = PyDict_GetItem(object, key); RET: Py_XDECREF(key); return; }

    这里的key用完一定得释放,因为这里的key只是为了获取到value值而已。

    2、对Python API了解不足

    static void *setData(void *pyObject, sg_UserData *ud) { PyObject *key = NULL; PyObject *object = (PyObject *)pyObject; PyObject *value = NULL; value = PyList_New(ud->len); PyList_SetItem(object, ud->idx, value); Py_XDECREF(value); Py_XDECREF(key); }

    这里虽然减少了引用计数,但是在python调用object里面数据的时候会报错的。因为PyList_SetItem这个函数不会增加value的计数。

    #define Py_XSETREF(op, op2) \ do { \ PyObject *_py_tmp = (PyObject *)(op); \ (op) = (op2); \ Py_XDECREF(_py_tmp); \ } while (0) int PyList_SetItem(PyObject *op, Py_ssize_t i, PyObject *newitem) { PyObject **p; // 一些判断 p = ((PyListObject *)op) -> ob_item + i; Py_XSETREF(*p, newitem); return 0; }

    由源码可见,PyList_SetItem仅仅是改变ob_item内元素的指向而已,而不像PyDict_SetItem这类函数会增加value的计数值。至于python为什么这么做,我也不清楚了。
    所以正确的写法是:

    static void *setData(void *pyObject, sg_UserData *ud) { PyObject *key = NULL; PyObject *object = (PyObject *)pyObject; PyObject *value = NULL; value = PyList_New(ud->len); Py_XINCREF(value); // <-- 增加这个 PyList_SetItem(object, ud->idx, value); Py_XDECREF(value); Py_XDECREF(key); }