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

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

问题描述

我想使用new和delete运算符来创建和销毁我的对象.

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

问题是python似乎将其分为几个阶段. tp_new,tp_init和tp_alloc用于创建,tp_del,tp_free和tp_dealloc用于销毁.然而,c ++只是具有新的功能,它可以分配并完全构造对象,而删除的对象则可以破坏并取消分配对象.

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.

我需要提供哪些python tp_ *方法,它们必须做什么?

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

我还希望能够直接在c ++中创建对象,例如"PyObject * obj = new MyExtensionObject(args);"我是否还需要以某种方式使新操作符过载以支持此操作?

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?

我还希望能够在python中扩展我的扩展类型,我需要做些特别的事情来支持它吗?

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?

我正在使用python 3.0.1.

I'm using python 3.0.1.

好的,tp_init似乎使对象对于我正在做的事情太易变(例如,获取一个Texture对象,在创建后更改内容是可以的,但是更改其基本方面,例如大小,位分隔等会破坏很多假设这些东西是固定的现有c ++东西).如果我不实现它,它将仅仅阻止人们在其构造之后调用__init__(或至少像tuple那样忽略该调用).或者如果在同一对象上多次调用tp_init,我是否应该有一些引发异常或异常的标志?

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

推荐答案

这些文档的文档位于 http://docs.python.org/3.0/c-api/typeobj.html http://docs.python.org/3.0/extending/newtypes.html 介绍如何制作自己的类型.

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为实例执行低级内存分配.这等效于malloc(),并将refcnt初始化为1.Python有它自己的分配器PyType_GenericAlloc,但是一种类型可以实现专门的分配器.

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与Python的__new__相同.与指向数据的指针相比,它通常用于将数据存储在实例本身中的不可变对象.例如,字符串和元组将其数据存储在实例中,而不是使用char *或PyTuple *.

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 *.

在这种情况下,tp_new根据输入参数找出需要多少内存,并调用tp_alloc获取内存,然后初始化必填字段. tp_new不需要调用tp_alloc.例如,它可以返回缓存的对象.

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与Python的__init__相同.您的大部分初始化工作都应在此函数中进行.

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

__new__和__init__之间的区别称为两阶段初始化两阶段初始化.

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

您说" c ++刚刚有新的",但这是不正确的. tp_alloc对应于C ++中的自定义竞技场分配器,__new__对应于自定义类型分配器(工厂函数),而__init__更类似于构造函数.最后一个链接详细讨论了C ++和Python风格之间的相似之处.

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.

也请阅读 http://www.python.org/download/releases/2.2/descrintro/了解有关__new__和__init__如何交互的详细信息.

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

您写道,您想直接在c ++中创建对象".这相当困难,因为至少您必须将对象实例化期间发生的所有Python异常转换为C ++异常.您可以尝试查看Boost :: Python以获得有关此任务的一些帮助.或者,您可以使用两阶段初始化. ;)

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天全站免登陆