Question

Je veux utiliser la nouvelle et supprimer les opérateurs pour créer et détruire mes objets.

Le problème est python semble briser en plusieurs étapes. tp_new, tp_init et tp_alloc pour la création et tp_del, tp_free et tp_dealloc pour la destruction. Cependant c ++ a tout nouveau qui alloue et construit entièrement l'objet et de suppression qui destructs et désalloue l'objet.

Lequel des tp_ python * méthodes dois-je fournir et ce que doivent-ils faire?

Aussi je veux être en mesure de créer l'objet directement en C ++ par exemple "PyObject * obj = new MyExtensionObject (args);" Ai-je besoin aussi de surcharger le nouvel opérateur d'une certaine façon de soutenir cela?

Je voudrais aussi être en mesure de sous-classe mes types d'extension en python, est-il quelque chose de spécial que je dois faire pour soutenir cela?

J'utilise python 3.0.1.

EDIT: ok, tp_init semble faire des objets un peu trop mutable pour ce que je fais (par exemple, prendre un objet Texture, modifier le contenu après la création est bien, mais changer les aspects fondamentaux de celui-ci, tels que la taille, bitdept, etc cassera beaucoup de choses existantes c ++ qui suppose ces sortes de choses sont fixes). Si je ne le mettre en œuvre, il va tout simplement arrêter les gens appeler __init__ après sa construction (ou au moins ignorer l'appel, comme le fait tuple). Ou devrais-je avoir un drapeau qui jette une exception ou somthing si tp_init est appelé plus d'une fois sur le même objet?

En dehors de cela, je pense que Ive a obtenu la plupart du reste triés.

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();
    }
    ...
};
Était-ce utile?

La solution

La documentation pour ces derniers est à http://docs.python.org/ 3,0 / c-IPV / typeobj.html et http://docs.python.org/3.0/extending/newtypes.html décrit comment faire votre propre type.

tp_alloc fait l'allocation de mémoire à faible niveau de l'instance. Cela équivaut à malloc (), plus initialiser le refcnt à 1. Python a son propre allocateur, PyType_GenericAlloc, mais un type peut mettre en œuvre un allocateur spécialisé.

tp_new est le même que celui __new__ Python. Il est généralement utilisé pour des objets immuables où les données sont stockées dans l'instance elle-même, par rapport à un pointeur vers les données. Par exemple, les chaînes et tuples stockent leurs données dans l'instance, au lieu d'utiliser un char * ou PyTuple *.

Dans ce cas, les chiffres tp_new la quantité de mémoire est nécessaire, en fonction des paramètres d'entrée et demande tp_alloc pour obtenir la mémoire, puis les champs initialise essentiels. tp_new n'a pas besoin d'appeler tp_alloc. Il peut par exemple renvoyer un objet mis en cache.

tp_init est le même que celui __init__ Python. La plupart de votre initialisation devrait être dans cette fonction.

La distinction entre __new__ et __init__ est appelée initialisation à deux étages de ou deux phases d'initialisation .

Vous dites " c ++ juste a nouveau " mais ce n'est pas correct. tp_alloc correspond un domaine personnalisé allocateur en C ++, __new__ correspond à un type personnalisé allocateur (fonction d'origine), et __init__ est plus comme le constructeur. Ce dernier lien discute plus sur les parallèles entre C ++ et le style Python.

lire également http://www.python.org/download/releases/2.2 / descrintro / pour plus de détails sur la façon dont __new__ et __init__ interagir.

Vous écrivez que vous voulez « créer l'objet directement dans c ++ ». C'est assez difficile, car au moins vous aurez à convertir des exceptions Python qui se sont produits lors de l'instanciation d'objets dans une exception C ++. Vous pourriez essayer de regarder Boost :: Python pour un peu d'aide dans cette tâche. Ou vous pouvez utiliser une initialisation en deux phases. ;)

Autres conseils

Je ne sais pas les API python du tout, mais si python divise l'allocation et l'initialisation, vous devriez être en mesure d'utiliser le placement nouveau.

par exemple:.

 // tp_alloc
 void *buffer = new char[sizeof(MyExtensionObject)];
 // tp_init or tp_new (not sure what the distinction is there)
 new (buffer) MyExtensionObject(args);
 return static_cast<MyExtensionObject*>(buffer);

 ...
 // tp_del
 myExtensionObject->~MyExtensionObject(); // call dtor
 // tp_dealloc (or tp_free? again I don't know the python apis)
 delete [] (static_cast<char*>(static_cast<void*>(myExtensionObject)));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top