首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python C-API对象分配

Python C-API对象分配
EN

Stack Overflow用户
提问于 2009-02-21 16:01:46
回答 2查看 6.1K关注 0票数 8

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

问题是python似乎把它分成了几个阶段。tp_new、tp_init和tp_alloc用于创建,tp_del、tp_free和tp_dealloc用于销毁。然而,c++只有分配和完全构造对象的new和销毁和释放对象的delete。

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

此外,我还希望能够直接在新的c++中创建对象,例如"PyObject *obj =MyExtensionObject(Args)“;我是否还需要以某种方式重载新操作符来支持这一点?

我也希望能够在python中子类化我的扩展类型,我需要做什么特殊的事情来支持它吗?

我使用的是python 3.0.1。

编辑:好吧,对于我正在做的事情来说,tp_init似乎让对象变得有点太多变了(例如,拿一个纹理对象来说,在创建之后改变内容是可以的,但改变它的基本方面,比如大小,位图等会破坏很多现有的c++东西,这些东西假设这些东西是固定的)。如果我不实现它,它会简单地停止人们在构造之后调用__init__ (或者至少忽略这个调用,就像元组一样)。或者,如果在同一对象上多次调用tp_init,我是否应该有一些标志来抛出异常或其他东西?

除此之外,我想我已经把剩下的大部分都整理好了。

代码语言:javascript
复制
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();
    }
    ...
};
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2009-02-21 17:25:30

关于这些的文档在http://docs.python.org/3.0/c-api/typeobj.html上,http://docs.python.org/3.0/extending/newtypes.html描述了如何创建自己的类型。

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

tp_new和Python的__new__是一样的。它通常用于不可变对象,其中数据存储在实例本身中,而不是指向数据的指针。例如,字符串和元组将其数据存储在实例中,而不是使用char *或PyTuple *。

对于这种情况,tp_new根据输入参数计算出需要多少内存,并调用tp_alloc来获取内存,然后初始化基本字段。tp_new不需要调用tp_alloc。例如,它可以返回缓存的对象。

tp_init和Python的__init__是一样的。你的大部分初始化工作应该在这个函数中完成。

__new__和__init__之间的区别称为two-stage initializationtwo-phase initialization

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

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

你写道你想“直接在c++中创建对象”。这相当困难,因为至少您必须将对象实例化过程中发生的任何Python异常转换为C++异常。您可以尝试使用Boost::Python来帮助完成这项任务。或者,您可以使用两阶段初始化。;)

票数 11
EN

Stack Overflow用户

发布于 2009-02-21 16:16:59

我对python API一无所知,但是如果python将分配和初始化分开,您应该能够使用placement new。

例如:

代码语言:javascript
复制
 // 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)));
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/573275

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档