8

オブジェクトの作成と破棄に new および delete 演算子を使用したいと考えています。

問題は、python がいくつかの段階に分かれているように見えることです。tp_new、tp_init、および tp_alloc は作成用であり、tp_del、tp_free、および tp_dealloc は破棄用です。ただし、c++ には、オブジェクトを割り当てて完全に構築する new と、オブジェクトを破棄して割り当てを解除する delete しかありません。

どの python tp_* メソッドを提供する必要があり、何をする必要がありますか?

また、「PyObject *obj = new MyExtensionObject(args);」など、C++ でオブジェクトを直接作成できるようにしたいと考えています。これをサポートするには、何らかの方法で new 演算子をオーバーロードする必要がありますか?

また、Python で拡張機能の型をサブクラス化できるようにしたいと考えています。これをサポートするために何か特別なことをする必要がありますか?

私はpython 3.0.1を使用しています。

編集:わかりました、tp_initは私がやっていることに対してオブジェクトを少し変更しすぎているようです(たとえば、Textureオブジェクトを取得し、作成後に内容を変更することは問題ありませんが、サイズ、bitdeptなどの基本的な側面を変更すると壊れますそのようなものが修正されていることを前提とする多くの既存のC++のもの)。私がそれを実装しない場合、構築された後に __init__ を呼び出す人々を単に停止します(または、少なくともタプルのように呼び出しを無視します)。または、同じオブジェクトで tp_init が複数回呼び出された場合に例外または何かをスローするフラグを用意する必要がありますか?

それとは別に、私は残りのほとんどをソートしたと思います。

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

2 に答える 2

11

これらのドキュメントは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__ の違いは、2 段階の初期化または2段階の初期化 と呼ばれます。

あなたは「c++ には new があるだけだ」と言いますが、それは正しくありません。tp_alloc は C++ のカスタム アリーナ アロケータに対応し、__new__ はカスタム型アロケータ (ファクトリ関数) に対応し、__init__ はコンストラクタに似ています。最後のリンクでは、C++ と Python スタイルの類似点について詳しく説明しています。

__new__ と __init__ の相互作用の詳細については、http: //www.python.org/download/releases/2.2/descrintro/ もお読みください。

「オブジェクトを直接 c++ で作成したい」と書いています。少なくとも、オブジェクトのインスタンス化中に発生したすべての Python 例外を C++ 例外に変換する必要があるため、これはかなり困難です。Boost::Python を見てみると、このタスクの助けが得られるかもしれません。または、2 フェーズの初期化を使用できます。;)

于 2009-02-21T17:25:29.800 に答える
0

Python API についてはまったくわかりませんが、Python が割り当てと初期化を分割する場合は、placement new を使用できるはずです。

例えば:

 // 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)));
于 2009-02-21T16:16:58.857 に答える