我和一个朋友一直在与各种Python的C ++包装玩弄最近四周,试图找到一个同时满足一些专业和业余爱好项目的需要。我们既磨练在 PyCxx 为重量轻,易于之间的良好平衡与同时躲着走接口一些Python的C API的最丑陋位。 PyCxx是不是非常强劲,当谈到但是暴露类型(即:它指示创建类型的工厂,而不是实现构造函数),而且我们一直在努力,才能在填补空白暴露我们的类型更实用的方式。为了弥补这些缺陷,我们转向C API。

这给我们留下了一些问题,但是,API文档似乎并没有这么深层次的覆盖(当它呢,答案是偶尔矛盾)。基本的首要问题很简单:什么是必须定义一个Python类型为基本类型的功能?我们已经发现,对于PyCxx类作为一个类型的函数,我们需要定义tp_new和tp_dealloc明确,并设置类型为模块属性,我们需要有Py_TPFLAGS_BASETYPE设置[我们的类型] - > tp_flags,但超越那我们仍然在黑暗中摸索。

下面是我们的代码迄今:

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'

其迷惑废话了我。这是因为如果从继承它完全隐藏基类!如果任何人都可以提供一些见解,我们缺什么,我们将不胜感激!谢谢!


编辑:好的,所以这张贴后约五秒钟我回忆的东西,我们本来想提前尝试。我添加以下代码以小猫 -

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

所以仍然在寻找一些帮助!谢谢!

有帮助吗?

解决方案

您必须声明kitty作为class new_style_class: public Py::PythonClass< new_style_class >。见simple.cxx和Python的测试用例在的http:// 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
>>> 

我最好的猜测是,C ++ getattr方法应该检查this.ob_type->tp_dict(当然这将是子类字典,如果this子类的实例),如果你不能找到在那里getattr_methods(见PyDict_和来电name API函数)。

另外,我不认为你应该设置tp_dealloc自己:我没有看到你的实现上PyCxx的默认extension_object_deallocator如何改进

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top