2010-10-14 10 views
5

Hallo,Cuenta de referencia de Python y tipos

Tengo algunos problemas para entender el recuento de referencias de Python. Lo que quiero hacer es devolver una tupla de C++ a python usando el módulo 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 

estoy no estaba seguro sobre el recuento de ref obj, así que intentó sys.getrefcount() y se 3. Creo que debería ser 2 (las funciones getrefcount hacen una ref sí).

Ahora no puedo hacer Py_DECREF() antes de la devolución en C++ porque el objeto se elimina. ¿Puedo disminuir el recuento de ref en Python?

edición ¿Qué ocurre con el recuento de ref cuando se llama a la función de conversión? No estoy seguro de la documentación a continuación. http://docs.python.org/library/ctypes.html#ctypes.cast

ctypes.cast (obj, tipo) Esta función es similar a la operador de conversión en C. Se devuelve una nueva instancia de tipo que apunta al mismo bloque de memoria como obj. type debe ser un tipo de puntero, y obj debe ser un objeto que pueda interpretarse como un puntero.

código

Respuesta

4

En investigaciones posteriores descubrí que se puede especificar el tipo de devolución de la función. http://docs.python.org/library/ctypes.html#callback-functions Esto hace que el molde sea obsoleto y el recuento de ref. Ya no es un problema.

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

Como no se dieron respuestas adicionales acepto mi nueva solución como la respuesta.

4

C++ parece ser una envoltura clásica utilizando el official C-API y que es un poco extraño ya que ctypes se utiliza por lo general para el uso de tipos clásicos c en Python (como int, float, etc ...).

Uso personalmente el C-API "solo" (sin tipos) pero en mi experiencia personal, no tiene que preocuparse por el contador de referencia en este caso ya que está devolviendo un tipo de pitón nativo con Py_BuildValue. Cuando una función devuelve un objeto, la propiedad del objeto devuelto se asigna a la función de llamada.

usted tiene que preocuparse acerca Py_XINCREF/Py_XDECREF (mejor que Py_INCREF/Py_DECREF porque acepta punteros NULL) sólo cuando se desea cambiar la propiedad del objeto:

Por ejemplo, se ha creado un envoltorio de un mapa en python (llamemos al objeto tipeado py_map). El elemento es de la clase C++ Foo y usted ha creado otro contenedor de python para ellos (llamémoslo py_Foo). Si crea una función que envuelva el operador [], se le va a devolver un objeto py_Foo en Python:

F = py_Map["key"] 

pero desde que se da la propiedad a la función que llama, se le llame al destructor cuando se elimina F ¡y el mapa en C++ contiene un puntero a un objeto desasignado!

La solución es escribir en C++ en el envoltorio de []:

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

debería echar un vistazo a la noción de borrowed and owned reference en Python.Esto es esencial para entender adecuadamente el contador de referencia.

+0

Pero creas un módulo python-c ¿verdad? Quería omitir eso y con ctypes puedes simplemente 'ctypes.cdll.LoadLibrary ('some.so')'. Entonces, el manejo del tipo de devolución es diferente. Con ctypes es 'ctypes.py_object'. Luego uso la función de conversión y no estoy seguro de cómo se maneja correctamente el recuento de ref. Ver mi edición – tauran

+0

Sí, de hecho, eso puede ser un poco más complicado ... Traté de leer el código fuente de cast() pero no tuve tiempo suficiente para investiagte correctamente. Trataré de echar un vistazo cuando tenga el tiempo suficiente y edite mi respuesta si encuentro algo que demuestre que ctypes toma la propiedad (si es el caso, tal vez debería considerar crear directamente un objeto python-c para eliminar estos problemas . Eso es bastante fácil ya que ya estás trabajando con PyObject) – ThR37

Cuestiones relacionadas