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

问题描述 投票:0回答:2

我有一个暴露了两个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__()也有效吗?

python c++ multiple-inheritance super boost-python
2个回答
2
投票

C ++层无法直接访问Python用于通过super自动执行超类调用的MRO信息。如果您使用Python的明确知识污染了C ++代码,您可以直接创建PySuper_Type的对象(必须使用两个参数调用;启用no-arg super的魔法将不可用)并使用它,但混合使用Python代码使用C ++代码会非常难看。

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

class Derived(MyClassA, MyClassB):
    # Must define __init__ even though you only defer to parent classes,
    # or only MyClassA will be created
    def __init__(self):
        MyClassA.__init__(self)
        MyClassB.__init__(self)
    def foo(self):
        MyClassA.foo(self)
        MyClassB.foo(self)

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()
© www.soinside.com 2019 - 2024. All rights reserved.