首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用PyCxx创建可继承的Python类型

使用PyCxx创建可继承的Python类型
EN

Stack Overflow用户
提问于 2009-02-14 03:44:08
回答 2查看 1.4K关注 0票数 3

我和一个朋友最近一直在玩各种Python,试图找到一个既满足专业项目又满足爱好项目的包装。我们都在PyCxx上磨练了一个很好的平衡,它是轻量级的和易于与之交互的,同时隐藏了Python中一些最丑陋的部分。然而,在公开类型时,PyCxx并不是非常健壮(即:它指示您创建类型工厂而不是实现构造函数),我们一直在努力填补空白,以便以更实用的方式公开类型。为了填补这些空白,我们转而使用gaps。

然而,这给我们留下了一些问题,即api文档似乎没有深入讨论(当它深入讨论时,答案有时是矛盾的)。基本的首要问题很简单: Python类型必须定义什么才能作为基类型?我们已经发现,要使PyCxx类作为类型运行,我们需要显式地定义tp_new和tp_dealloc,并将类型设置为模块属性,并且需要在类型->tp_标志上设置Py_TPFLAGS_BASETYPE,但除此之外,我们仍然在黑暗中摸索。

到目前为止,我们的代码如下:

代码语言:javascript
复制
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测试代码如下所示:

代码语言:javascript
复制
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就会给我们这样的结果:

代码语言:javascript
复制
AttributeError: 'kitty' object has no attribute 'speak'

把我搞糊涂了。就好像从它继承完全隐藏了基类一样!如果有人能对我们缺少的东西提供一些见解,我们将不胜感激!谢谢!

编辑:好的,在发布这篇文章后的大约5秒钟,我想起了我们之前想要尝试的一些东西。我给kitty添加了以下代码-

代码语言:javascript
复制
virtual Py::Object getattr( const char *name ) {
    return getattr_methods( name );
}

现在我们正在用Python对两个小猫喵喵叫!但是,我仍然没有完全理解,因为现在我明白了:

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

所以还在找人帮忙!谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2009-02-16 22:17:13

您必须声明kittyclass new_style_class: public Py::PythonClass< new_style_class >。请参阅simple.cxxhttp://cxx.svn.sourceforge.net/viewvc/cxx/trunk/CXX/Demo/Python3/的Python测试用例。

Python2.2引入了新的样式类,这些类允许用户对内置类型(比如新的内置类型)进行子类化。继承在您的示例中不起作用,因为它定义了一个旧的样式类。

票数 3
EN

Stack Overflow用户

发布于 2009-02-16 00:35:00

我在PyCxx上只做了一点点工作,而且我不是编译器,但我怀疑您所看到的类似于下面的情况,用纯Python表示:

代码语言:javascript
复制
>>> 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是子类的一个实例,当然这将是子类的dict ),并且只有在没有在其中找到name时才调用getattr_methods (参见PyDict_ API函数)。

此外,我认为您不应该自己设置tp_dealloc:我不知道您的实现如何改进PyCxx的默认extension_object_deallocator

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/548442

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档