Boost.Python:如何调用super()方法?

时间:2018-02-21 15:24:45

标签: python c++ multiple-inheritance super boost-python

我有一个暴露了两个C ++类的模块,它们都有方法foo()

struct MyClassA{
    void foo() { std::cout << "MyClassA::foo()" << std::endl; }
};

struct MyClassB{
    void foo() { std::cout << "MyClassB::foo()" << std::endl; }
};

BOOST_PYTHON_MODULE(my_module){
    class_<MyClassA>("MyClassA", init<>()).def("foo", &MyClassA::foo);
    class_<MyClassB>("MyClassB", init<>()).def("foo", &MyClassB::foo);
}

在Python中,我创建了一个派生自两个类的类:

from my_module import MyClassA, MyClassB

class Derived(MyClassA, MyClassB):
    def foo(self):
        super().foo()  # should be unnessessary - doesn't work anyway

a = MyClassA()
a.foo()  # works
b = MyClassB()
b.foo()  # works
d = Derived()
d.foo()  # only prints 'MyClassA::foo()'

现在,我希望d.foo()致电MyClassA.foo()以及MyClassB.foo()。但是虽然Derived.mro()看起来很好:

[<class '__main__.Derived'>, <class 'my_module.MyClassA'>, <class 'my_module.MyClassB'>, <class 'Boost.Python.instance'>, <class 'object'>]

..仅调用MyClassA.foo()

如何让C ++方法调用super()方法?这对__init__()也适用吗?

2 个答案:

答案 0 :(得分:2)

C ++层无法直接访问Python用于通过private static String[] args; private static ConfigurableApplicationContext context; public static void main(String[] args) { Main.args = args; Main.context = SpringApplication.run(Main.class, args); } public static void restart() { // close previous context context.close(); // and build new one Main.context = SpringApplication.run(Main.class, args); } 自动执行超类调用的MRO信息。如果您使用Python的明确知识污染了C ++代码,则可以直接创建super的对象(必须使用两个参数调用;启用no-arg PySuper_Type的魔法将不可用)和使用它,但将Python代码与C ++代码混合起来会非常难看。

在实践中,使用Boost.Python的最佳建议可能是the same as for pybind11(一种C ++ 11特定的仅限头的工具,其服务于类似的目的而不依赖于整个Boost生态系统),以及那里推荐的方法是显式调用C ++级父类方法,而不是通过super隐式调用。没有合理的方法将C ++和Python方法合并到多重继承中,这种方法不会导致使用Python特定代码无可靠地污染非Python代码。 super的方法是:

pybind11

答案 1 :(得分:0)

我当前的方法(改编自this回答)需要某种处理super() - 手动调用的包装器。结果类不再需要任何特殊处理:

C ++代码:

struct MyClassA{
    void foo() { std::cout << "MyClassA::foo()" << std::endl; }
};

struct MyClassB{
    void foo() { std::cout << "MyClassB::foo()" << std::endl; }
};

BOOST_PYTHON_MODULE(my_module){
    class_<MyClassA>("MyClassACpp", init<>()).def("foo", &MyClassA::foo);
    class_<MyClassB>("MyClassBCpp", init<>()).def("foo", &MyClassB::foo);
}

<强>包装

from my_module import MyClassACpp, MyClassBCpp

def call_super(cls, instance, method, *args):
    mro = instance.__class__.mro()
    for next_class in mro[mro.index(cls) + 1:]:
        if not hasattr(next_class, method):
            continue
        if next_class.__module__ in {'Boost.Python', 'builtins'}:
            continue
        getattr(next_class, method)(instance, *args)
        if next_class.__module__ != 'my_module':
            break

class MyClassA(MyClassACpp):
    def __init__(self):
        call_super(MyClassA, self, '__init__')
        print('MyClassA.__init__()')

    def foo(self):
        call_super(MyClassA, self, 'foo')

class MyClassB(MyClassBCpp):
    def __init__(self):
        call_super(MyClassB, self, '__init__')
        print('MyClassB.__init__()')

    def foo(self):
        call_super(MyClassB, self, 'foo')

<强>用法:

class Derived(MyClassA, MyClassB):
    def foo(self):
        super().foo()

d = Derived()
d.foo()

<强>输出:

MyClassA.__init__()
MyClassB.__init__()
MyClassA::foo()
MyClassB::foo()