Python подсчет ссылок и ctypes - PullRequest
       29

Python подсчет ссылок и ctypes

5 голосов
/ 14 октября 2010

Алло,

У меня возникли проблемы с подсчетом ссылок на python. Я хочу вернуть кортеж из c ++ в python с помощью модуля ctypes.

C ++:

PyObject* foo(...)
{

  ...
  return Py_BuildValue("(s, s)", value1, value2);
}

Python:

pointer = c_foo(...) # c_foo loaded with ctypes
obj = cast(pointer, py_object).value

Я не был уверен в количестве ссылок на obj, поэтому я попытался sys.getrefcount() и получил 3. Я думаю, что это должно быть 2 (getrefcount функция делает один ref сам).

Теперь я не могу сделать Py_DECREF() до возврата в C ++, потому что объект удаляется. Могу ли я уменьшить количество ссылок в Python?

редактировать Что происходит с подсчетом ссылок, когда вызывается функция приведения? Я не совсем уверен из документации ниже. http://docs.python.org/library/ctypes.html#ctypes.cast

ctypes.cast (obj, type) Эта функция аналогична оператору приведения в C. Она возвращает новый экземпляр типа, который указывает на тот же блок памяти, что и obj. type должен быть указателем, а obj должен быть объектом, который можно интерпретировать как указатель.

Ответы [ 2 ]

5 голосов
/ 17 октября 2010

В ходе дальнейших исследований я обнаружил, что можно указать тип возвращаемого значения функции. http://docs.python.org/library/ctypes.html#callback-functions Это делает приведение устаревшим, и количество ссылок больше не является проблемой.

clib = ctypes.cdll.LoadLibrary('some.so')
c_foo = clib.c_foo
c_foo.restype = ctypes.py_object

Поскольку никаких дополнительных ответов не было, я принимаю мое новое решение в качестве ответа.

4 голосов
/ 14 октября 2010

Ваш код на c ++ выглядит как классическая оболочка, использующая официальный код C-API , и это немного странно, поскольку ctypes обычно используется для использования классических типов c в python (таких как int, float и т. Д.). .).

Я лично использую C-API "один" (без ctypes), но из моего личного опыта вам не нужно беспокоиться о счетчике ссылок в этом случае, так как вы возвращаете нативный тип Python с Py_BuildValue. Когда функция возвращает объект, владение возвращенного объекта передается вызывающей функции.

Вам следует беспокоиться о Py_XINCREF / Py_XDECREF (лучше, чем Py_INCREF / Py_DECREF, поскольку он принимает указатели NULL), только если вы хотите изменить владельца объекта:

Например, вы создали оболочку карты в python (назовем типизированный объект py_map). Элемент имеет класс C ++ Foo, и вы создали для них другую оболочку Python (назовем ее py_Foo). Если вы создадите функцию, которая обернет оператор [], вы собираетесь вернуть объект py_Foo в python:

F = py_Map["key"]

но так как право собственности передается вызывающей функции, вы будете вызывать деструктор при удалении F, а карта на c ++ содержит указатель на освобожденный объект!

Решение состоит в том, чтобы написать на С ++ в оболочке []:

...
PyObject* result; // My py_Foo object
Py_XINCREF(result); // transfer the ownership
return result;
}

Вам следует взглянуть на понятие заимствованной и находящейся в собственности ссылки в python. Это важно для правильного понимания счетчика ссылок.

...