Ich möchte die neuen und löschenden Operatoren zum Erstellen und Zerstören meiner Objekte verwenden.Python C-API Objekt Zuweisung
Das Problem ist Python scheint es in mehrere Stufen zu brechen. tp_new, tp_init und tp_alloc für die Erstellung und tp_del, tp_free und tp_dealloc für die Zerstörung. Allerdings hat C++ nur neue, die das Objekt zuweist und vollständig konstruiert und löscht, was das Objekt destruiert und freigibt.
Welche der python tp_ * Methoden muss ich bereitstellen und was müssen sie tun?
Auch ich möchte in der Lage sein, das Objekt direkt in C++ zB "PyObject * obj = new MyExtensionObject (args);" Muss ich den neuen Betreiber auch irgendwie überlasten, um dies zu unterstützen?
Ich möchte auch in der Lage sein, meine Erweiterungstypen in Python Unterklasse, gibt es etwas Besonderes, das ich tun muss, um dies zu unterstützen?
Ich benutze Python 3.0.1.
EDIT: ok, tp_init scheint Objekte etwas zu veränderlich zu machen für das, was ich mache (zB ein Textur-Objekt nehmen, den Inhalt nach der Erstellung ändern, aber grundlegende Aspekte ändern, wie Größe, bitdept, etc. wird viele existierende C++ - Sachen zerstören, die davon ausgehen, dass diese Dinge behoben sind. Wenn ich es nicht implementiere, wird es einfach Leute stoppen, die __init__ NACH ihrer Konstruktion aufrufen (oder zumindest den Aufruf ignorieren, wie Tupel das tut). Oder sollte ich ein Flag haben, das eine Exception oder etwas auslöst, wenn tp_init mehr als einmal für dasselbe Objekt aufgerufen wird?
Abgesehen davon glaube ich, dass ive den Rest größtenteils sortiert hatte.
extern "C"
{
//creation + destruction
PyObject* global_alloc(PyTypeObject *type, Py_ssize_t items)
{
return (PyObject*)new char[type->tp_basicsize + items*type->tp_itemsize];
}
void global_free(void *mem)
{
delete[] (char*)mem;
}
}
template<class T> class ExtensionType
{
PyTypeObject *t;
ExtensionType()
{
t = new PyTypeObject();//not sure on this one, what is the "correct" way to create an empty type object
memset((void*)t, 0, sizeof(PyTypeObject));
static PyVarObject init = {PyObject_HEAD_INIT, 0};
*((PyObject*)t) = init;
t->tp_basicsize = sizeof(T);
t->tp_itemsize = 0;
t->tp_name = "unknown";
t->tp_alloc = (allocfunc) global_alloc;
t->tp_free = (freefunc) global_free;
t->tp_new = (newfunc) T::obj_new;
t->tp_dealloc = (destructor)T::obj_dealloc;
...
}
...bunch of methods for changing stuff...
PyObject *Finalise()
{
...
}
};
template <class T> PyObjectExtension : public PyObject
{
...
extern "C" static PyObject* obj_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
{
void *mem = (void*)subtype->tp_alloc(subtype, 0);
return (PyObject*)new(mem) T(args, kwds)
}
extern "C" static void obj_dealloc(PyObject *obj)
{
~T();
obj->ob_type->tp_free(obj);//most of the time this is global_free(obj)
}
...
};
class MyObject : PyObjectExtension<MyObject>
{
public:
static PyObject* InitType()
{
ExtensionType<MyObject> extType();
...sets other stuff...
return extType.Finalise();
}
...
};
Platzierung 'neu' wäre intuitiv, aber leider' neu (p) Klasse (args); 'führt vor dem Aufruf des Konstruktors eine Null-Initialisierung durch und löscht Werte, die der Python-Zuordnungs/Initialisierungs-Code in das Objekt geschrieben hat Speicher (z. B. die Referenzzählung). Getrennt davon ist die Verwendung von 'new char [n]' dann überlagernden Strukturen gefährlich, da die garantierte Speicherausrichtung nur 1 ist. –