Pergunta

Eu quero usar as novas e excluir operadores para criar e destruir meus objetos.

O problema é python parece dividi-lo em várias etapas. tp_new, tp_init e tp_alloc para a criação e tp_del, tp_free e tp_dealloc para a destruição. No entanto c ++ só tem novos que aloca e totalmente constrói o objeto e excluir que destrói e desaloca o objeto.

Qual dos tp_ python * métodos que eu preciso para fornecer e o que devem fazer?

Também quero ser capaz de criar o objeto diretamente no c ++ por exemplo, "PyObject * obj = new MyExtensionObject (args);" Será que eu também preciso sobrecarregar o novo operador de alguma forma para suportar isso?

Eu também gostaria de ser capaz de subclasse meus tipos de extensão em python, há especial qualquer coisa que eu preciso fazer para suportar isso?

Eu estou usando python 3.0.1.

EDIT: ok, tp_init parece fazer objetos um pouco mutável para o que eu estou fazendo (por exemplo, tomar um objeto textura, alterar o conteúdo após a criação é bom, mas alterar aspectos fundamentais do mesmo, tais como, tamanho, bitdept, etc vai quebrar muitas material c existente ++ que assume esse tipo de coisas são fixos). Se eu não implementá-lo vai simplesmente parar de pessoas chamando __init__ APÓS seu construídas (ou pelo menos ignorar a chamada, como tupla faz). Ou devo ter alguma bandeira que lança uma exceção ou somthing se tp_init é chamado mais de uma vez no mesmo objeto?

Além de que eu acho que o ive obteve a maioria do 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();
    }
    ...
};
Foi útil?

Solução

A documentação para estes é em http://docs.python.org/ 3.0 / c-api / typeobj.html http://docs.python.org/3.0/extending/newtypes.html descreve como fazer o seu próprio tipo.

tp_alloc faz a alocação de memória de baixo nível para a instância. Isto é equivalente a malloc (), além de inicializar o refcnt a 1. Python tem o seu próprio alocador, PyType_GenericAlloc, mas um tipo pode implementar um alocador especializado.

tp_new é o mesmo que __new__ do Python. É geralmente usado para objetos imutáveis, onde os dados são armazenados no próprio exemplo, em comparação com um ponteiro para dados. Por exemplo, cordas e tuplos armazenar os dados no exemplo, em vez de usar um char * ou um PyTuple *.

Para este caso, figuras tp_new quanta memória é necessária, com base nos parâmetros de entrada e chamadas tp_alloc para obter a memória, em seguida, inicializa os campos essenciais. tp_new não precisa tp_alloc chamada. Ele pode, por exemplo, devolver um objeto em cache.

tp_init é o mesmo que __init__ do Python. A maior parte de sua inicialização deve ser nesta função.

A distinção entre __new__ e __init__ é chamado de dois estágios de inicialização ou inicialização> duas fases.

Você diz " c ++ acaba de novo ", mas isso não é correto. tp_alloc corresponde uma arena alocador costume em C ++, __new__ corresponde a um tipo personalizado alocador (uma função de fábrica), e init é mais parecido com o construtor. Esse último elo discute mais sobre os paralelos entre C ++ e estilo Python.

Além disso, leia http://www.python.org/download/releases/2.2 / descrintro / para detalhes sobre como __new__ e __init__ interagem.

Você escreve que deseja "criar o objeto diretamente no c ++". Isso é bastante difícil, porque pelo menos você vai ter que converter quaisquer excepções Python que ocorreram durante a instanciação de objetos em uma exceção de C ++. Você pode tentar olhar para boost :: Python para alguma ajuda com esta tarefa. Ou você pode usar uma inicialização de duas fases. ;)

Outras dicas

Eu não sei as APIs Python em tudo, mas se divide python-se alocação e inicialização, você deve ser capaz de usar posicionamento novo.

por exemplo:.

 // 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top