Python的C-API对象分配 [英] Python C-API Object Allocation‏

查看:326
本文介绍了Python的C-API对象分配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用new和delete操作符用于创建和销毁我的对象。

问题是蟒蛇似乎它分成几个阶段。 tp_new,tp_init和tp_alloc创造和tp_del,tp_free和tp_dealloc销毁。不过C ++只是有新的分配这完全和构造对象,并删除其解构并释放对象。

这蟒蛇tp_ *方法,我需要和提供什么他们必须做的?

此外,我希望能够直接在C ++中如创建对象的PyObject * OBJ =新MyExtensionObject(参数);我也需要重载新的运营商以某种方式支持呢?

我也想能够继承我的扩展类型的蟒蛇,有什么特别的,我需要做支持呢?

我使用python 3.0.1。

编辑:
好吧,tp_init似乎使物体有点太可变的我在做什么(如采取纹理对象,更改后的内容创造是好的,但变化如大小,bitdept等将打破很多它的基本方面现有的C ++的东西,假设这些类的东西是固定的)。如果我不执行,将它简单地阻止人们调用__init__后的构造(或至少忽略该呼叫,像元组一样)。或者我应该有一些标志,抛出一个异常或者财产以后,如果tp_init被称为不止一次在同一对象上?

除此之外,我认为香港专业教育学院拿到剩下的大部分来分类的。

 的externC
{
    //创建+毁灭
    *的PyObject global_alloc(PyTypeObject *类型,Py_ssize_t项)
    {
        返回(*的PyObject)新的char [类型 - > tp_basicsize +项目*类型 - > tp_itemsize]。
    }
    无效global_free(无效* MEM)
    {
        删除[](字符*)MEM;
    }
}
模板<类T>类ExtensionType
{
    PyTypeObject * T;
    ExtensionType()
    {
        T =新PyTypeObject(); //不知道在这一个,什么是正确的方法来创建一个空的对象类型
        memset的((无效*)T,0,sizeof的(PyTypeObject));
        静态PyVarObject初始化= {PyObject_HEAD_INIT,0};
        *((*的PyObject)T)= INIT;        T-> tp_basicsize = sizeof的(T);
        叔> tp_itemsize = 0;        T-> tp_name =未知;        T-> tp_alloc =(allocfunc)global_alloc;
        T-> tp_free =(freefunc)global_free;
        T-> tp_new =(newfunc)T :: obj_new;
        T-> tp_dealloc =(析构函数)T :: obj_dealloc;
        ...
    }
    ...一堆改变的东西...方法
    *的PyObject最后确定()
    {
    ...
    }
};
模板<类T> PyObjectExtension:公众的PyObject
{
...
    为externC静态的PyObject * obj_new(PyTypeObject *亚型的PyObject * ARGS,*的PyObject kwds)
    {
        void *的纪念品=(无效*)subtype-> tp_alloc(亚型,0);
        返回(*的PyObject)新(MEM)笔(参数,kwds)
    }
    为externC静态无效obj_dealloc(*的PyObject OBJ)
    {
        〜T();
        obj-> ob_type-> tp_free(OBJ); //大多是这种global_free的时间(OBJ)
    }
...
};
类为MyObject:PyObjectExtension<&MyObject的GT;
{
上市:
    静态的PyObject * InitType()
    {
        ExtensionType<&MyObject的GT; extType();
        ...设置其他的东西...
        返回extType.Finalise();
    }
    ...
};


解决方案

这些文档是的 http://docs.python.org/3.0/c-api/typeobj.html
http://docs.python.org/3.0/extending/newtypes.html 介绍了如何使自己的类型。

tp_alloc做为实例的低级内存分配。这相当于对malloc(),加上初始化为1。Python有它自己的分配器,PyType_GenericAlloc的refcnt,但一个类型可以实现一个专门的分配器。

tp_new相同Python的__new__。它通常用于在数据被存储在该实例本身相比,指针数据不变对象。例如,字符串和元组存储数据的实例,而不是使用一个char *或PyTuple *

有关该情况下,tp_new算出多少存储器是需要的,基于输入参数,并调用tp_alloc来获得存储器,然后初始化必要字段。 tp_new并不需要调用tp_alloc。例如,它可以返回缓存的对象。

tp_init是一样的Python的__init__。大多数的初始化应该在这个函数。

__new__和__init__之间的区别称为两级初始化或<一href=\"http://groups.google.com/group/comp.lang.python/browse_thread/thread/b129dc656f4d0c8b/e43ae56909c3c00a?lnk=gst&q=two-phase+init#e43ae56909c3c00a\"相对=nofollow>两相初始化

您说的 C ++只是还新的,但是这是不正确的。 tp_alloc相当于C ++中的自定义的舞台上分配器,__new__对应一个自定义类型分配器(工厂函数),__init__更像是构造函数。这最后一个环节将讨论更多关于C ++和Python样式之间的相似之处。

另请阅读 http://www.python.org/download/releases/2.2 / descrintro /,详细了解如何__new__和__init__互动

您写要直接在C ++创建对象++。这是相当困难的,因为你至少得转换对象实例化到一个C ++异常期间发生的任何异常的Python。你可以尝试寻找的boost ::对Python的一些帮助,这个任务。或者你可以使用两阶段初始化。 ;)

I want to use the new and delete operators for creating and destroying my objects.

The problem is python seems to break it into several stages. tp_new, tp_init and tp_alloc for creation and tp_del, tp_free and tp_dealloc for destruction. However c++ just has new which allocates and fully constructs the object and delete which destructs and deallocates the object.

Which of the python tp_* methods do I need to provide and what must they do?

Also I want to be able to create the object directly in c++ eg "PyObject *obj = new MyExtensionObject(args);" Will I also need to overload the new operator in some way to support this?

I also would like to be able to subclass my extension types in python, is there anything special I need to do to support this?

I'm using python 3.0.1.

EDIT: ok, tp_init seems to make objects a bit too mutable for what I'm doing (eg take a Texture object, changing the contents after creation is fine, but change fundamental aspects of it such as, size, bitdept, etc will break lots of existing c++ stuff that assumes those sort of things are fixed). If I dont implement it will it simply stop people calling __init__ AFTER its constructed (or at least ignore the call, like tuple does). Or should I have some flag that throws an exception or somthing if tp_init is called more than once on the same object?

Apart from that I think ive got most of the rest sorted.

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();
    }
    ...
};

解决方案

The documentation for these is at http://docs.python.org/3.0/c-api/typeobj.html and http://docs.python.org/3.0/extending/newtypes.html describes how to make your own type.

tp_alloc does the low-level memory allocation for the instance. This is equivalent to malloc(), plus initialize the refcnt to 1. Python has it's own allocator, PyType_GenericAlloc, but a type can implement a specialized allocator.

tp_new is the same as Python's __new__. It's usually used for immutable objects where the data is stored in the instance itself, as compared to a pointer to data. For example, strings and tuples store their data in the instance, instead of using a char * or a PyTuple *.

For this case, tp_new figures out how much memory is needed, based on the input parameters, and calls tp_alloc to get the memory, then initializes the essential fields. tp_new does not need to call tp_alloc. It can for example return a cached object.

tp_init is the same as Python's __init__. Most of your initialization should be in this function.

The distinction between __new__ and __init__ is called two-stage initialization, or two-phase initialization.

You say "c++ just has new" but that's not correct. tp_alloc corresponds a custom arena allocator in C++, __new__ corresponds to a custom type allocator (a factory function), and __init__ is more like the constructor. That last link discusses more about the parallels between C++ and Python style.

Also read http://www.python.org/download/releases/2.2/descrintro/ for details about how __new__ and __init__ interact.

You write that you want to "create the object directly in c++". That's rather difficult because at the least you'll have to convert any Python exceptions that occurred during object instantiation into a C++ exception. You might try looking at Boost::Python for some help with this task. Or you can use a two-phase initialization. ;)

这篇关于Python的C-API对象分配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆