2009-02-21 12 views
5

オブジェクトの作成と破棄にnew演算子とdelete演算子を使用したいと思います。Python C-APIオブジェクトの割り当て

問題は、Pythonがいくつかの段階に分けるようです。作成のためのtp_new、tp_init、およびtp_alloc、破棄のためのtp_del、tp_free、およびtp_deallocしかし、C++には、オブジェクトを割り当てて完全に構築し、そのオブジェクトを破棄したり、割り当てを解除したりする新しいものがあります。

どのpython tp_ *メソッドを提供する必要があり、どのようにしなければなりませんか?

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

また、私の拡張機能の種類をPythonでサブクラス化できるようにしたいと思いますが、これをサポートするために何か特別なことはありますか?

私はpython 3.0.1を使用しています。テクスチャオブジェクトを作成して、作成後に内容を変更するなど、オブジェクトのサイズをあまりにも変更可能にしているようですが、サイズ、サイズなどの基本的な側面を変更してください。 bitdeptなどは、そのようなものが修正されていると仮定して、既存のC++のものをたくさん破ります)。私がそれを実装していないと、それは単に、構築された後に(または少なくともタプルのように呼び出しを無視して)__init__を呼び出す人々を止めるでしょう。または、同じオブジェクトに対してtp_initが複数回呼び出された場合は、例外をスローするフラグが必要ですか?

それ以外は、私はiveが残りの大部分を分類していると思います。

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

答えて

11

これらのドキュメントは、http://docs.python.org/3.0/c-api/typeobj.htmlhttp://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 initializationまたはtwo-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を見てみると、この作業の助けになるかもしれません。または、2段階の初期化を使用することもできます。 ;)

0

私はPython APIをまったく知らないですが、Pythonが割り当てと初期化を分割すると、新しい配置を使用できるはずです。

例えば:

// 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))); 
+1

配置は直感的ですが、残念ながら 'new(p)Class(args);'はコンストラクタを呼び出す前にゼロ初期化を行い、Pythonの割り当て/初期化コードがオブジェクトに入れた値を消去しますメモリ(例えば、参照カウント)。これとは別に、 'new char [n]'を使うと、保証されたメモリアライメントが1にすぎないので、構造をオーバーレイすることは危険です。 –

関連する問題