On 2012-03-27, Stefan Behnel wrote:
SIP und SWIG sind automatische Wapper-Generatoren. Entweder, sie tun was du willst - oder eben nicht. Und wenn nicht, dann wird's im besten Fall nur irre kompliziert und im schlechtesten Fall kannst du das Tool wechseln.
Wobei das händische Einbinden von C-Code in Python nun wirklich nicht schwer ist und durch die Python C-API gut unterstützt wird. Dazu vllt. auch gleich eine Frage. Gegeben sei folgende Ausgangssituation: Ein Pythonprogramm ruft eine in C geschriebene Extension mit einem Parameter auf, der aus einer in ein numpy.array konvertierten Python-Liste von Objekten besteht. Das C-Programm nutzt dazu einen Zeiger auf dieses nun eng gepackte Array von Zeigern und wählt durch einen geeigneten Algorithmus aus dieser Objektmenge einige aus, die nun in eine Python-Liste von Python-Listen von Objekten gekapselt zurückgegeben werden. Freigegeben oder verändert wird keines der beim Aufruf der Extension übergebenen Objekte. Die Python-Ergebnisliste wird in C so konstruiert: ... PyObject *r = PyList_New(0); ... static PyObject *VLP_asPyList(VectorlistP *vl) { PyObject *result = PyList_New(vl->length); int i; for (i=0; i<vl->length; i++) PyList_SetItem(result, i, Py_BuildValue("O", vl->list[i]->anomaly)); // ^^^^^^^^^^^^^^^^^^^^ // Zeiger auf eins der ursprünglichen Objekte return result; } ... PyList_Append(r, VLP_asPyList(&bestResult)); ... return r; Nun gibt es ja für jedes Python-Objekt einen Referenzzähler, der beim Konstruieren dieser Liste eigentlich inkrementiert werden müsste, und ich nehme auch stark an, dass das durch Verwendung dieser Funktionen gegeben ist. Allerdings fand ich dazu nichts Eindeutiges in der Doku. Ist obige Vorgehensweise korrekt? Bernd -- "Die Antisemiten vergeben es den Juden nicht, dass die Juden Geist haben - und Geld." [Friedrich Nietzsche]
Bernd Nawothnig, 27.03.2012 17:03:
Ein Pythonprogramm ruft eine in C geschriebene Extension mit einem Parameter auf, der aus einer in ein numpy.array konvertierten Python-Liste von Objekten besteht. Das C-Programm nutzt dazu einen Zeiger auf dieses nun eng gepackte Array von Zeigern und wählt durch einen geeigneten Algorithmus aus dieser Objektmenge einige aus, die nun in eine Python-Liste von Python-Listen von Objekten gekapselt zurückgegeben werden. Freigegeben oder verändert wird keines der beim Aufruf der Extension übergebenen Objekte. Die Python-Ergebnisliste wird in C so konstruiert: ... PyObject *r = PyList_New(0); ... static PyObject *VLP_asPyList(VectorlistP *vl) { PyObject *result = PyList_New(vl->length); int i;
for (i=0; i<vl->length; i++) PyList_SetItem(result, i, Py_BuildValue("O", vl->list[i]->anomaly)); // ^^^^^^^^^^^^^^^^^^^^ // Zeiger auf eins der ursprünglichen Objekte return result; } ... PyList_Append(r, VLP_asPyList(&bestResult));
Hier war ein "extend()" gemeint, oder?
return r;
Zum Vergleich der (mangels umgebendem Code und Daten natürlich ungetestete) äquivalente Code in Cython: return [ item.anomaly for item in bestResult.list[:bestResult.length] ] Finde ich hübscher und übersichtlicher. Stefan
Bernd Nawothnig, 27.03.2012 17:03:
for (i=0; i<vl->length; i++) PyList_SetItem(result, i, Py_BuildValue("O", vl->list[i]->anomaly));
Was mir gerade auffällt: ist das nicht grober Unfug? Warum sollte das besser sein als for (i=0; i<vl->length; i++) { PyObject* obj = vl->list[i]->anomaly; Py_INCREF(obj); PyList_SET_ITEM(result, i, obj); } ? Langsamer ist es in jedem Fall, aber besser? Selbst in dem Fall, dass eines der "anomaly" Felder NULL ist, ignorierst du doch schließlich einfach die Exception, die Python dann für dich setzt. Übrigens auch unschön, so etwas zu tun, aber findet sich in handgeschriebenem Code eben öfter mal. Deshalb empfehle ich ja auch keinem, sowas von Hand zu schreiben. Stefan
participants (2)
-
Bernd Nawothnig
-
Stefan Behnel