2010-10-14 14 views
5

Ciao,Numero di riferimento e tipi di codice Python

Ho alcuni problemi a comprendere il conteggio dei riferimenti di Python. Quello che voglio fare è restituire una tupla da C++ a python usando il modulo 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 

Sono non era sicuro circa il conteggio ref di obj, così ho provato sys.getrefcount() e ottenuto 3. Penso che dovrebbe essere 2 (le funzioni getrefcount fanno un ref stesso).

Ora non riesco a rendere Py_DECREF() prima del ritorno in C++ perché l'oggetto viene eliminato. Posso diminuire il numero di ref in python?

modificare Cosa succede al conteggio ref quando la funzione getto si chiama? Non sono molto sicuro dalla documentazione qui sotto. http://docs.python.org/library/ctypes.html#ctypes.cast

ctypes.cast (obj, type) Questa funzione è simile all'operatore getto in C. restituisce una nuova istanza di tipo che punta allo stesso blocco di memoria come obj. type deve essere un tipo di puntatore e obj deve essere un oggetto che può essere interpretato come un puntatore.

codice

risposta

4

Su ulteriori ricerche ho scoperto che è possibile specificare il tipo di ritorno della funzione. http://docs.python.org/library/ctypes.html#callback-functions Questo rende obsoleto il cast e il conteggio dei ref non è più un problema.

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

Poiché non sono state fornite ulteriori risposte, accetto la mia nuova soluzione come risposta.

4

vostro C++ sembra essere un involucro classico utilizzando il official C-API ed è un po 'strano in quanto ctypes di solito è usato per l'utilizzo di tipi c classici in python (come int, float, ecc ...).

Io uso personalmente la C-API "sola" (senza i tipi) ma sulla mia esperienza personale, non devi preoccuparti del contatore di riferimento in questo caso poiché stai restituendo un tipo nativo di python con Py_BuildValue. Quando una funzione restituisce un oggetto, la proprietà dell'oggetto viene restituita alla funzione chiamante.

si deve preoccupare di Py_XINCREF/Py_XDECREF (meglio di Py_INCREF/Py_DECREF perché accetta puntatori NULL) solo quando si desidera cambiare la proprietà dell'oggetto:

Per esempio, è stato creato un involucro di una mappa in python (chiamiamo l'oggetto digitato py_map). L'elemento è di classe C++ Foo e per loro è stato creato un altro wrapper python (chiamiamolo py_Foo). Se si crea una funzione che avvolgono l'operatore [], che si sta per restituire un oggetto py_Foo in python:

F = py_Map["key"] 

ma dal momento che la proprietà è dato alla funzione chiamante, si chiamerà il distruttore quando si elimina F e la mappa in C++ contiene un puntatore a un oggetto deallocato!

La soluzione è scrivere in C++ nella confezione di []:

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

Si dovrebbe prendere uno sguardo alla nozione di borrowed and owned reference in python.Questo è essenziale per capire correttamente il contatore di riferimento.

+0

Ma si crea un modulo python-c giusto? Volevo saltare questo e con i ctype puoi semplicemente 'ctypes.cdll.LoadLibrary ('some.so')'. Quindi la gestione del tipo di ritorno è diversa. Con i ctypes è 'ctypes.py_object'. Quindi uso la funzione cast e non sono sicuro di come il conteggio ref sia gestito correttamente. Vedi la mia modifica. – tauran

+0

Sì, certo, potrebbe essere un po 'più complicato ... Ho provato a leggere il codice sorgente di cast() ma non ho avuto abbastanza tempo per investire correttamente. Cercherò di dare un'occhiata quando avrò abbastanza tempo e modificherò la mia risposta se trovo qualcosa che dimostri che i ctype ne assumono la proprietà (se è il caso, forse dovresti considerare di creare direttamente un oggetto python-c per eliminare questi problemi Questo è abbastanza facile dato che stai già lavorando con PyObject) – ThR37

Problemi correlati