3

友人と私は最近、さまざまな Python C++ ラッパーをいじり回しており、いくつかの専門的なプロジェクトと趣味のプロジェクトの両方のニーズを満たすものを見つけようとしています。Python C api の最も醜い部分を隠しながら、軽量であることとインターフェイスが簡単であることのバランスが取れているため、私たちは両方ともPyCxxに磨きをかけてきました。ただし、PyCxx は型の公開に関してはそれほど堅牢ではありません (つまり、コンストラクターを実装するのではなく、型ファクトリを作成するように指示します)。私たちは型をより機能的な方法で公開するためにギャップを埋めることに取り組んできました。 . これらのギャップを埋めるために、C API に目を向けます。

しかし、これにより、いくつかの疑問が残りました。API のドキュメントではあまり詳しく説明されていないようです (また、説明されている場合、答えが矛盾する場合があります)。基本的な包括的な質問は次のとおりです: Python 型が基本型として機能するには、何を定義する必要がありますか? PyCxx クラスが型として機能するためには、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 のすべてのビットをコメントアウトすると、スクリプトが実行され、猫は問題なくニャーと鳴きますが、meanKitty クラスのコメントを外すと、Python は突然次のように表示します。

AttributeError: 'kitty' object has no attribute 'speak'

それは私のがらくたを混乱させます。それを継承すると、基本クラスが完全に隠されているようです。私たちが欠けているものについて誰かが洞察を提供できれば、それはありがたいです! ありがとう!


編集: オーケー、これを投稿してから約 5 秒後に、以前に試してみたかったことを思い出しました。次のコードをキティに追加しました-

virtual Py::Object getattr( const char *name ) {
    return getattr_methods( name );
}

そして今、私たちは Python で両方の子猫にニャーと鳴いています! ただし、まだ完全ではありません。

Traceback (most recent call last):
    File "d:\Development\Junk Projects\PythonCxx\Toji.py", line 12, in <module>
    meanKitty.scratch()
AttributeError: scratch

だからまだ助けを探しています!ありがとう!

4

2 に答える 2

3

kittyとして宣言する必要がありclass new_style_class: public Py::PythonClass< new_style_class >ます。http://cxx.svn.sourceforge.net/viewvc/cxx/trunk/CXX/Demo/Python3/simple.cxxの Python テスト ケースを参照してください。

Python 2.2 では新しいスタイルのクラスが導入されました。これにより、ユーザーは組み込み型 (新しい組み込み型など) をサブクラス化できます。古いスタイルのクラスを定義しているため、この例では継承が機能しませんでした。

于 2009-02-16T22:17:13.573 に答える
1

私は 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
>>> 

私の最善の推測では、C++getattrメソッドはチェックしthis.ob_type->tp_dict(サブクラスのインスタンスの場合はもちろんサブクラスの dict になります)、そこに見つからない場合にthisのみ呼び出す必要があります (PyDict_ API 関数を参照)。getattr_methodsname

また、自分で設定するべきではないと思いますtp_dealloc: あなたの実装が PyCxx の default でどのように改善されるかわかりませんextension_object_deallocator

于 2009-02-16T00:35:00.270 に答える