Search code examples
python-c-api

Extending python with C: trying to swap list elements


I am to build a C module for Python 3.7, that swaps two list elements. Here is my code, where indexes of two elements and list are read:

static PyObject *st_change(PyObject *self, PyObject *args){
  PyObject *pList;
  PyObject *tmp1;
  PyObject *tmp2;
  int i,j;
  Py_ssize_t n;

  if (!PyArg_ParseTuple(args, "O!ll", &PyList_Type, &pList,&i,&j)) {
    PyErr_SetString(PyExc_TypeError, "parameters are wrong.");
    return NULL;
    }

  n = PyList_Size(pList);
  tmp1 = PyList_GetItem(pList,i);       
  tmp2 = PyList_GetItem(pList,j);
  PyList_SetItem(pList,i,tmp2);
  PyList_SetItem(pList,j,tmp1);
  Py_INCREF(pList);

  return pList;
}

This works for one-dimensional lists, but when I try to swap elements in list of lists, Python shuts down. For example, when a call

my_module.st_change([1,2,3],0,1)

the result is

[2,1,3]

and when I call

my_module.st_change([[1,2,3],[4,5,6],[7,8,9]],0,1)

python shell restsarts

I am completely new to C Python API, so would really appreciate if someone could point me in the right direction. Thank you


Solution

  • You're losing a reference to tmp1. PyList_SetItem discards a reference to the item already in that position, so when you do PyList_SetItem(pList,i,tmp2); you tmp1 gets decreffed and probably deallocated. You get away with it for int because there are typically lots of references to small int values.

    Before the calls to PyList_SetItem add Py_INCREF(tmp1); Py_INCREF(tmp2);