2010-10-14 18 views
5

Hallo,Python-Referenzzähler und Ctypes

Ich habe einige Probleme, die Python-Referenzzahl zu verstehen. Was ich tun möchte, ist ein Tupel von C++ zu Python mit dem Ctypes-Modul zurückgeben.

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 

Ich bin war über die ref Graf von obj nicht sicher, so habe ich versucht, sys.getrefcount() und bekam 3. Ich denke, es sollte 2 sein (die getrefcount Funktionen macht einen Ref selbst).

Jetzt kann ich Py_DECREF() vor der Rückkehr in C++ nicht machen, weil das Objekt gelöscht wird. Kann ich die Ref-Anzahl in Python verringern?

bearbeiten Was ist mit dem Verweiszähler geschieht, wenn die Umsetzungsfunktion genannt wird? Ich bin mir nicht ganz sicher, was in der Dokumentation unten steht. http://docs.python.org/library/ctypes.html#ctypes.cast

ctypes.cast (obj, Typ) Diese Funktion ist ähnlich der Umwandlungsoperator in C. Sie eine neue Instanz des Typs zurückgibt, die auf den gleichen Speicherblock wie obj zeigt. type muss ein Zeigertyp sein, und obj muss ein Objekt sein, das als Zeiger interpretiert werden kann.

Antwort

4

Bei weiteren Recherchen fand ich heraus, dass man den Rückgabetyp der Funktion angeben kann. http://docs.python.org/library/ctypes.html#callback-functions Dies macht die Besetzung obsolet und die Ref-Zählung ist kein Problem mehr.

Da keine zusätzlichen Antworten gegeben wurden, akzeptiere ich meine neue Lösung als Antwort.

4

C++ Code scheint ein klassisches Wrapper, um die official C-API verwenden und es ist ein bisschen komisch, da ctypes in der Regel für die Verwendung von klassischen C-Typen in Python verwendet wird (wie int, float, etc ...).

Ich benutze persönlich die C-API "allein" (ohne Ctypes), aber auf meine persönliche Erfahrung müssen Sie sich in diesem Fall keine Gedanken über den Referenzzähler machen, da Sie einen nativen Python-Typ mit Py_BuildValue zurückgeben. Wenn eine Funktion ein Objekt zurückgibt, wird der Besitz des zurückgegebenen Objekts an die aufrufende Funktion übergeben.

Sie haben über Py_XINCREF/Py_XDECREF sorgen nur (besser als Py_INCREF/Py_DECREF weil es NULL-Zeiger übernimmt), wenn Sie den Besitz des Objekts ändern möchten:

Zum Beispiel haben Sie einen Wrapper einer Karte erstellt in Python (nennen wir das typisierte Objekt py_map). Das Element gehört zur C++ Klasse Foo und Sie haben einen anderen Python-Wrapper für sie erstellt (nennen wir es py_Foo). Wenn Sie eine Funktion erstellen, die den Operator [] wickeln, Sie werden ein py_Foo Objekt in Python zurück:

F = py_Map["key"] 

aber da der Besitz an die aufrufende Funktion gegeben ist, werden Sie die destructor aufrufen, wenn Sie F löschen und die Karte in C++ enthält einen Zeiger auf ein freigegebenes Objekt!

Die Lösung ist in C++ in der Hülle von [] zu schreiben:

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

Sie sollten einen Blick auf den Begriff der borrowed and owned reference in Python.Dies ist wichtig, um den Referenzzähler richtig zu verstehen.

+0

Aber Sie erstellen ein Python-C-Modul richtig? Ich wollte das überspringen und mit ctypes kann man einfach 'ctypes.cdll.LoadLibrary ('some.so')'. Die Handhabung des Rückgabetyps ist also anders. Bei Ctypes ist es 'ctypes.py_object'. Dann benutze ich die Cast-Funktion und ich bin mir nicht sicher, wie die ref count korrekt behandelt wird. Siehe meine Bearbeitung. – tauran

+0

Ja in der Tat, das kann ein bisschen komplizierter sein ... Ich habe versucht, die Code-Quelle von cast() zu lesen, aber ich hatte nicht genug Zeit, um richtig zu untersuchen. Ich werde versuchen, einen Blick darauf zu werfen, wenn ich genug Zeit habe und meine Antwort editiere, wenn ich etwas finde, das beweist, dass ctypes das Eigentum übernimmt (wenn das der Fall ist, solltest du vielleicht ein Python-c-Objekt erstellen, um diese Probleme zu beseitigen Das ist ziemlich einfach, da Sie bereits mit PyObject arbeiten) – ThR37