Domanda

Vorrei utilizzare il nuovo ed eliminare gli operatori per la creazione e la distruzione miei oggetti.

Il problema è pitone sembra spezzare in diverse fasi. tp_new, tp_init e tp_alloc per la creazione e tp_del, tp_free e tp_dealloc per la distruzione. C ++ Tuttavia ha solo nuovi che alloca e completamente costruisce l'oggetto ed eliminare, che distrugge e rilascia l'oggetto.

Quale delle tp_ pitone * metodi fanno ho bisogno di fornire e che cosa devono fare?

Anche io voglio essere in grado di creare l'oggetto direttamente in C ++ per esempio "PyObject * obj = new MyExtensionObject (args);" Avrò anche bisogno di sovraccaricare il nuovo operatore in qualche modo per sostenere questo?

Mi piacerebbe anche essere in grado di sottoclasse miei tipi di estensione in python, c'è qualcosa di speciale ho bisogno di fare per sostenere questo?

Sto usando Python 3.0.1.

EDIT: ok, tp_init sembra rendere gli oggetti un po 'troppo mutevole per quello che sto facendo (ad esempio, prendere un oggetto Texture, cambiando il contenuto dopo la creazione va bene, ma cambiare aspetti fondamentali di essa, come, dimensioni, bitdept, ecc romperà un sacco di c esistente roba ++ che assume quel tipo di cose sono fissi). Se io non attuarla sarà semplicemente smettere di chiamare le persone __init__ dopo la sua costruzione (o almeno ignorare la chiamata, come tuple fa). O dovrei avere qualche bandiera che genera un'eccezione o somthing se tp_init è chiamato più di una volta sullo stesso oggetto?

A parte questo penso che Ive ha ottenuto la maggior parte del resto ordinato.

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();
    }
    ...
};
È stato utile?

Soluzione

La documentazione di questi è a http://docs.python.org/ 3.0 / c-api / typeobj.html e http://docs.python.org/3.0/extending/newtypes.html descrive come rendere il proprio tipo.

tp_alloc fa l'allocazione di memoria a basso livello per l'istanza. Ciò equivale a malloc (), oltre a inizializzare il RefCnt a 1. Python ha il proprio allocatore, PyType_GenericAlloc, ma un tipo può implementare un allocatore specializzata.

tp_new è la stessa di __new__ di Python. Di solito è utilizzato per oggetti immutabili cui i dati sono memorizzati nella istanza stessa, rispetto ad un puntatore a dati. Ad esempio, stringhe e tuple memorizzano i loro dati nel caso, invece di utilizzare un char * o un PyTuple *.

Per questo caso, tp_new capisce la quantità di memoria necessaria, in base ai parametri di input, e chiede tp_alloc per ottenere la memoria, quindi inizializza i campi essenziali. tp_new non ha bisogno di chiamare tp_alloc. Si può ad esempio restituire un oggetto in cache.

tp_init è la stessa di __init__ di Python. La maggior parte del vostro inizializzazione dovrebbe essere in questa funzione.

La distinzione tra __new__ e __init__ è chiamato inizializzazione due stadi o due fasi di inizializzazione .

Tu dici " C ++ appena è nuovo ", ma questo non è corretto. tp_alloc corrisponde un'arena allocatore personalizzato in C ++, __new__ corrisponde ad un tipo personalizzato allocatore (una funzione di fabbrica), e __init__ è più simile al costruttore. Questo ultimo anello discute più sui parallelismi tra C ++ e Python stile.

Anche a leggere le http://www.python.org/download/releases/2.2 / descrintro / per i dettagli su come __new__ e __init__ interagire.

Si scrive che si vuole "creare l'oggetto direttamente in C ++". Questo è piuttosto difficile, perché almeno si dovrà convertire tutte le eccezioni Python che si sono verificati nel corso di istanze di oggetti in un'eccezione C ++. Si potrebbe provare a guardare Boost :: Python per un aiuto con questo compito. In alternativa è possibile utilizzare una di inizializzazione a due fasi. ;)

Altri suggerimenti

Non conosco le API di pitone a tutti, ma se pitone divide l'allocazione e l'inizializzazione, si dovrebbe essere in grado di utilizzare nuova collocazione.

per esempio:.

 // 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)));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top