Pregunta

Quiero usar el nuevo y borrar los operadores para crear y destruir mis objetos.

El problema es pitón parece dividirla en varias etapas. tp_new, tp_init y tp_alloc para la creación y tp_del, tp_free y tp_dealloc para su destrucción. Sin embargo c ++ acaba de nuevo que asigna y totalmente construye el objeto y borrar que destructs y desasigna el objeto.

¿Cuál de los métodos tp_ pitón * necesito para proporcionar y qué deben hacer?

También quiero ser capaz de crear el objeto directamente en C ++ por ejemplo, "PyObject * obj = new MyExtensionObject (args);" Yo también tenga que sobrecargar el nuevo operador de alguna manera a apoyar esto?

También me gustaría ser capaz de subclase mis tipos de extensiones en Python, ¿hay algo especial que deba hacer para apoyar esto?

Estoy usando Python 3.0.1.

EDIT: ok, tp_init parece hacer que los objetos un poco demasiado mutable de lo que estoy haciendo (por ejemplo, tomar un objeto Texture, cambiando el contenido después de la creación está bien, pero cambiar aspectos fundamentales de la misma, tales como, el tamaño, bitdept, etc va a romper un montón de c ++ existente cosas que asume ese tipo de cosas son fijos). Si yo no ponerlo en práctica va a impedir que la gente simplemente llamando __init__ después de su construcción (o al menos ignorar la llamada, al igual que lo hace tupla). O debería tener alguna bandera que lanza una excepción o somthing si tp_init se llama más de una vez en el mismo objeto?

Aparte de eso creo ive consiguió la mayoría del resto ordenados.

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();
    }
    ...
};
¿Fue útil?

Solución

La documentación de estos es en http://docs.python.org/ 3,0 / c-api / typeobj.html y http://docs.python.org/3.0/extending/newtypes.html describe cómo hacer su propio tipo.

tp_alloc hace la asignación de memoria de bajo nivel para la instancia. Esto es equivalente a malloc (), además de inicializar el refcnt a 1. Python tiene su propia asignador, PyType_GenericAlloc, sino un tipo puede implementar un asignador especializado.

tp_new es la misma que __new__ de Python. Por lo general se utiliza para los objetos inmutables, donde los datos se almacenan en la propia instancia, en comparación con un puntero a los datos. Por ejemplo, las cadenas y las tuplas almacenan sus datos en la instancia, en lugar de utilizar un char * o una PyTuple *.

En este caso, tp_new se da cuenta de la cantidad de memoria que se necesita, sobre la base de los parámetros de entrada, y pide tp_alloc para conseguir la memoria, a continuación, inicializa los campos esenciales. tp_new no necesita llamar tp_alloc. Por ejemplo, puede devolver un objeto en caché.

tp_init es la misma que __init__ de Python. La mayor parte de su inicialización debería estar en esta función.

La distinción entre __new__ y __init__ se llama inicialización de dos etapas o dos fases de inicialización .

Usted dice " C ++ acaba de nuevo ", pero eso no es correcto. tp_alloc corresponde un asignador de arena de costumbre en C ++, __new__ corresponde a un asignador de tipo personalizado (una función de fábrica), y __init__ es más como el constructor. Ese último eslabón discute más sobre los paralelismos entre C ++ y Python estilo.

http://www.python.org/download/releases/2.2 / descrintro / para obtener más información acerca de cómo __new__ y __init__ interactuar.

Usted escribe que desea "crear el objeto directamente en C ++". Eso es bastante difícil porque al menos usted tiene que convertir cualquier excepción de Python que se produjeron durante la instanciación de objetos en una excepción de C ++. Es posible que intente buscar en Boost :: Python para un poco de ayuda con esta tarea. O puede utilizar una inicialización de dos fases. ;)

Otros consejos

No sé las API de Python en absoluto, pero si pitón divide la asignación e inicialización, usted debería ser capaz de utilizar la colocación de nuevo.

por ejemplo:.

 // 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)));
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top