正在将构造函数添加到Boost.Python子类导致参数不匹配

2024-05-16 14:40:57 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图用Python作为我的C++项目的脚本语言,所以我达到了Boost.Python使任务不那么乏味。我有一个C++类(Script系统),它负责保存和执行Python脚本。在

namespace py = boost::python;

class ScriptSystem : public System
{
    public:
    virtual void execute_scripts() override;

    void addToPyGlobals(const OtherSystemsPtr&);
    void addScript(IScript*);

    private:
    std::vector<IScript *> scripts;
    py::dict python_globals;        
};

Python脚本应该是被包装的C++接口的子类,名为IScript。在

^{pr2}$

我设法向Python公开了ScriptSystem类和IScript接口,它几乎可以正常工作。我可以创建IScript的新实例并将它们传递给ScriptSystem而不会有任何麻烦。我可以创建重写tick(self)的子类,只要它们不定义构造函数,我就可以开始了。在

namespace py = boost::python;

class ScriptWrapper : public Script::IScript, public py::wrapper<Script::IScript>
{
    public:
    void tick()const override
    {
        // Check for Python override
        if(py::override f = this->get_override("tick")) {
            std::cout << "Found Python override"
                      << std::endl;
            f();
            return;
        }

        // If there is no override, call the default implementation
        std::cout << "No Python override found, calling C++ implementation." 
                  << std::endl;
        this->Script::IScript::tick();
        return;
    }

    void default_tick() const {
        return this->Script::IScript::tick();
    }
};


BOOST_PYTHON_MODULE(_script)
{
    py::class_<ScriptSystem, boost::noncopyable>("ScriptSystem")
        .def("add_script", &ScriptSystem::addScript);

    py::class_<ScriptWrapper, boost::noncopyable>("Script")
        .def("tick", &Script::IScript::tick, &ScriptWrapper::default_tick);

    py::implicitly_convertible<ScriptWrapper*, Script::IScript*>();
}

我可以向类添加数据属性,但是添加__init__(self)会导致问题。例如,此代码段执行得很好:

(RemoteShell)
>>> from script import Script
>>> class One(Script):
...     def tick(self):
...             print "I'm a script!"
...             print "My value is {}".format(One.value)
... 
>>> One.value = 5
>>> one = One()              
>>> script_system.add_script(one)

但是这个代码失败了:

(RemoteShell)
>>> from script import Script
>>> class Two(Script):
...     def __init__(self):
...             self.count = 0
...     def tick(self):
...             if self.count % 2 == 0:
...                     print "Tick"
...             else:
...                     print "Tock"
...             self.count += 1
... 
>>> two = Two()
>>> script_system.add_script(two)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
ArgumentError: Python argument types in
    ScriptSystem.add_script(ScriptSystem, Two)
did not match C++ signature:
    add_script(ScriptSystem {lvalue}, Script::IScript*)

所以,我想我的问题是:这里发生了什么?!我不明白为什么向脚本的Python子类(IScript的Python包装器)添加构造函数会导致参数不匹配错误。在


Tags: pyselfadddefscriptpublicclassstd
1条回答
网友
1楼 · 发布于 2024-05-16 14:40:57

当派生类提供^{}方法时,它必须显式调用其基类__init__方法,以确保实例的基类部分正确初始化。在这种情况下,Two实例的Script部分没有正确初始化,导致Boost.Python是基于C++类型的故障调度。在

要解决此问题,请考虑更改:

class Two(Script):
    def __init__(self):
        self.count = 0

收件人:

^{pr2}$

下面是一个完整的最小示例:

#include <boost/python.hpp>

/// @brief Mockup type.
class spam {};

/// @brief Mockup function that takes spam types.
void action(spam*) {}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<spam>("Spam");
  python::def("action", &action);
}

交互式使用:

>>> import example
>>> example.action(example.Spam())
>>> class MoreSpam(example.Spam):
...     def __init__(self):
...         pass
... 
>>> example.action(MoreSpam())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    example.action(MoreSpam)
did not match C++ signature:
    action(spam*)
>>> class EvenMoreSpam(example.Spam):
...     def __init__(self):
...         example.Spam.__init__(self)
... 
>>> example.action(EvenMoreSpam())

相关问题 更多 >