Расширение python с помощью C: попытка поменять элементы списка - PullRequest
0 голосов
/ 20 апреля 2020

Я собираюсь построить модуль C для Python 3.7, который поменяет местами два элемента списка. Вот мой код, где читаются индексы двух элементов и списка:

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;
}

Это работает для одномерных списков, но когда я пытаюсь поменять элементы в списке списков, Python закрывается. Например, при вызове

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

результат равен

[2,1,3]

, а когда я звоню

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

python перезапуск оболочки

Я совершенно новичок в C Python API, поэтому буду очень признателен, если кто-то сможет указать мне правильное направление. Спасибо

1 Ответ

0 голосов
/ 21 апреля 2020

Вы теряете ссылку на tmp1. PyList_SetItem отбрасывает ссылку на элемент, уже находящийся в этой позиции , поэтому, когда вы делаете PyList_SetItem(pList,i,tmp2);, вы tmp1 дешифруются и, вероятно, освобождаются. Вы получаете это за int, потому что обычно есть много ссылок на маленькие значения int.

Перед вызовами PyList_SetItem добавьте Py_INCREF(tmp1); Py_INCREF(tmp2);

...