使用boost.python,如何扩展类的__dir__函数?

时间:2018-06-28 07:02:42

标签: python c++ boost boost-python

我有一个导出到python的类,在纯python中,我可以通过以下方式轻松扩展 dir 函数:

 def __dir__(self):
    attr = list(self.__attributesMap().keys())
    return attr + dir(type(self))

所以我在c ++类中添加了一个dir函数,但是问题是如何通过boost.python在c ++中获取dir(type(self))的值?

1 个答案:

答案 0 :(得分:1)

不幸的是,我认为这是不可能的。我们可以部分声明该类:

struct test {
    void foo() { printf("foo!\n"); }
    void bar() { printf("bar!\n"); }
    void baz() {}
};

// define initial tclass
auto tclass = class_<test>("test")
    .def("foo", &test::foo)
    .def("bar", &test::bar);

然后扩展 dir 函数:

auto cur = tclass();
tclass.def("__dir__",
    make_function(
        [cur] (object) -> object {
            list curdir = (list)object(handle<>(PyObject_Dir(cur.ptr())));
            curdir.append("hello");
            return curdir;
        },
        default_call_policies(),
        boost::mpl::vector<object, object>()));

但是,这样做,使用对象本身的实例,我们得到一个无限循环,因为它只是重新绑定了内部指针。而且,如果我们尝试调用PyObject_Type并在其上调用PyObject_Dir,则会返回Boost.Python.class,因为它是boost :: python公开类的实际类型,并且没有添加正确的对象(因为这是动态完成的。

如果我们使用python,我们可以看到这一点:

>>> dir(skunk.test)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__instance_size__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'foo']

>>> dir(type(skunk.test))
['__abstractmethods__', '__base__', '__bases__', '__basicsize__', '__call__', '__class__', '__delattr__', '__dict__', '__dictoffset__', '__doc__', '__eq__', '__flags__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__instancecheck__', '__itemsize__', '__le__', '__lt__', '__module__', '__mro__', '__name__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasscheck__', '__subclasses__', '__subclasshook__', '__weakrefoffset__', 'mro']

类的类型不是我们想要的。因此,您不能使用类本身(无限循环),也不能使用类型(不是像Python那样的类型),还剩下什么?您也许可以定义两次该类,然后使用其中一个来填充另一个的目录,但这似乎是多余的。最好只手动编写dir函数来对类上的其他方法进行硬编码。无论如何,您都必须手动对其进行.def()。