PyCxxと継承Pythonのタイプを作成します
-
23-08-2019 - |
質問
友人と私は両方のいくつかの専門家や趣味のプロジェクトのニーズに合ったものを見つけるためにしようと、最近、様々なPythonのC ++ラッパーの周りいじるされています。我々は両方の離れ隠しながらとインターフェースをとるように、軽量で使いやすいものとの間に良好なバランスとして PyCxx の上で磨いてきましたPythonのC APIを醜いビットの一部。 PyCxxは、種類をさらすことになると、それほど強くないが(すなわち:それは型工場を作るのではなく、コンストラクタを実装するように指示)、そして私たちは、より機能的に私たちのタイプを公開するために、ギャップを埋めるに取り組んでいます。これらのギャップを埋めるために、我々は、C APIに回します。
これは、APIドキュメントがはるかに深さでカバーしていないようだ(とそれがないとき、答えは時折矛盾している)こと、しかし、いくつかの質問で私たちを残しています。基本的な包括的な質問は、単にこれです:Pythonの型は基本型として機能するために定義する必要がありますか? > tp_flagsが、超えた - 私たちは、PyCxxクラスは型として機能させるために、我々は我々がPy_TPFLAGS_BASETYPEは[私たちのタイプを]に設定されている必要があることを明示的にtp_newとtp_deallocを定義し、モジュールの属性としてタイプを設定する必要があり、かつ検出されませんでした我々はまだ暗闇の中で手探りしていること。
ここで我々のコードは、これまでのところです。
class kitty : public Py::PythonExtension<kitty> {
public:
kitty() : Py::PythonExtension<kitty>() {}
virtual ~kitty() {}
static void init_type() {
behaviors().name("kitty");
add_varargs_method("speak", &kitty::speak);
}
static PyObject* tp_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) {
return static_cast<PyObject*>(new kitty());
}
static void tp_dealloc(PyObject *obj) {
kitty* k = static_cast<kitty*>(obj);
delete k;
}
private:
Py::Object speak(const Py::Tuple &args) {
cout << "Meow!" << endl;
return Py::None();
}
};
// cat Module
class cat_module : public Py::ExtensionModule<cat_module> {
public:
cat_module() : Py::ExtensionModule<cat_module>("cat") {
kitty::init_type();
// Set up additional properties on the kitty type object
PyTypeObject* kittyType = kitty::type_object();
kittyType->tp_new = &kitty::tp_new;
kittyType->tp_dealloc = &kitty::tp_dealloc;
kittyType->tp_flags |= Py_TPFLAGS_BASETYPE;
// Expose the kitty type through the module
module().setAttr("kitty", Py::Object((PyObject*)kittyType));
initialize();
}
virtual ~cat_module() {}
};
extern "C" void initcat() {
static cat_module* cat = new cat_module();
}
そして、我々のPythonのテストコードは次のようになります:
import cat
class meanKitty(cat.kitty):
def scratch(self):
print "hiss! *scratch*"
myKitty = cat.kitty()
myKitty.speak()
meanKitty = meanKitty()
meanKitty.speak()
meanKitty.scratch()
好奇心ビットは、あなたがコメントした場合、すべてのmeanKittyが出ビット、スクリプトが実行され、猫はうまくmeowsていますが、meanKittyクラスのコメントを解除する場合は、突然のPythonは私たちにこれを与えることです
AttributeError: 'kitty' object has no attribute 'speak'
どの私のがらくたを混乱させる。それは完全に基本クラスを隠す継承かのようです!誰もが我々が欠けているものにいくつかの洞察を提供することができれば、それをいただければ幸いです!ありがとう!
<時間>EDIT:さて、これを投稿した後、私たちは先に試してみたかった何かを思い出さ5秒程度そう。私はキティに次のコードを追加しました -
virtual Py::Object getattr( const char *name ) {
return getattr_methods( name );
}
そして今、我々は、Pythonの両方のキティにmeowingています!まだない、完全にそこに、しかし、今、私はこれを取得するのでます:
Traceback (most recent call last):
File "d:\Development\Junk Projects\PythonCxx\Toji.py", line 12, in <module>
meanKitty.scratch()
AttributeError: scratch
だから、まだいくつかの助けを探して!ありがとう!
解決
あなたはkitty
としてclass new_style_class: public Py::PythonClass< new_style_class >
を宣言しなければなりません。 でhttp simple.cxx
とPythonのテストケースを参照してください:// CXX .svn.sourceforge.net /のViewVC / CXX /トランク/ CXX /デモ/のpython3 / に。
はPython 2.2導入された新しいスタイルのクラス(のようなあなたの新しいビルトインタイプ)。それは古いスタイルのクラスを定義するため、継承はあなたの例では動作しませんでした。
他のヒント
私はPyCxxと仕事のほんの少しをやった、と私は、コンパイラではないんだけど、私はあなたが見ているものを疑うことは、純粋なPythonで表現されるよう、次のような状況に似ています:
>>> class C(object):
... def __getattribute__(self, key):
... print 'C', key
...
>>> class D(C):
... def __init__(self):
... self.foo = 1
...
>>> D().foo
C foo
>>>
私の最高の推測では、あなたがそこにあるgetattr
(PyDict_を参照を見つけることに失敗した場合にのみthis.ob_type->tp_dict
をして呼び出すC ++ this
方法は、(getattr_methods
サブクラスのインスタンスならば、当然のことながらサブクラス辞書になります)name
を確認するべきであるということですAPI関数)。
また、私はあなた自身をtp_dealloc
設定しなければならないとは思わない:私はあなたの実装がPyCxxのデフォルトextension_object_deallocator
に改善方法を見ていない。