【问题标题】:SWIG/Python: Unable to access referenced parameter in Python callbackSWIG/Python:无法访问 Python 回调中的引用参数
【发布时间】:2021-11-11 07:20:32
【问题描述】:

在 SWIG 中,我有一个在 Python 中继承的封装 C++ 基类。 C++ 端调用 Python 派生类的回调,效果很好。不幸的是,回调的参数之一是作为引用传递的。访问此参考会产生:

致命的未处理异常:SWIG 导向器方法错误。检测到错误 调用“Base.Start”时

test.i

%module(directors="1", allprotected="1") test
%feature("director") Base;

class Base
{
    public:
        virtual bool Start(const Property& config) = 0; // PASSED AS REFERENCE

};

enum PropertyType{PT_REAL, PT_STRING};
class Property
{
    public:
        PropertyType GetType() const;
        int GetSize() const;
};

在 Python 中,Start 被正确回调/调用。不幸的是,调用GetType()GetSize() 会产生上述错误。调用作为指针传递的参数的函数很好。

import test

class PyClient(test.Base):
    def Start(self, config):
        config_size = config.GetSize() // YIELDS ERROR
        config_type = config.GetType() // YIELDS ERROR
        return True

我想我需要将参数 Property 从引用转换为指针,但我不清楚这在 SWIG 中是如何工作的。

更新

似乎调用回调中的参数与在Python 端创建时的基础类型不同。

def Start(self, config):
    prop_test = test.Property()
    type_test = prop_test.GetType() #FINE

    type_test2 = config.GetType() # ERROR

当在Start()Python 端创建Property (prop_test) 时,其类型为

<mds.Property; proxy of <Swig Object of type 'Property *' at 0x000001CC24DA3D80> >

而传递的属性有一个类型

<Swig Object of type 'Base::Property *' at 0x000001CC24CBE1E0>

我想知道这是否是预期的,或者这可能会导致根本问题。

痛饮 4.0.2

任何帮助将不胜感激。

【问题讨论】:

  • 创建一个minimal reproducible example。这不会建立复制,我对填补空白的猜测对我有用。您不需要任何特殊处理,我只是从您的部分代码中做了最少的工作以使其编译和运行。
  • 是的,根据您的更新,如果没有代理包装器,它将无法正常工作。它是指向 Python 的不透明指针。在我的示例中,无论是由 Python 还是 C++ 代码创建,都有一个代理包装器,那么您如何将 PyClient 实例从 Python 传递到 C++ 中?你没有表现出来。 再次minimal reproducible example
  • Aslo,您使用的是什么版本的 SWIG?我正在使用 4.0.2(最新)。

标签: python c++ inheritance callback swig


【解决方案1】:

您没有提供可重现的示例,所以我只是填补了缺失代码的空白并且它起作用了。如果有帮助,这是我的工作示例:

test.i:

%module(directors="1", allprotected="1") test

%feature("director") Base;

%inline %{
enum PropertyType{PT_REAL, PT_STRING};
class Property
{
    PropertyType m_prop;
    int m_size;
public:
    Property(PropertyType prop, int size) : m_prop(prop), m_size(size) {}
    PropertyType GetType() const { return m_prop; }
    int GetSize() const { return m_size; }
};

class Base
{
public:
    virtual bool Start(const Property& config) = 0;
    virtual ~Base() {}
};

void demo(Base* obj) {
    Property prop(PT_STRING,2);
    obj->Start(prop);
}
%}

ex.py:

import test

class PyClient(test.Base):
    def Start(self, config):
        config_size = config.GetSize()
        config_type = config.GetType()
        print(f'{config_size=} {config_type=}')
        return True

p = PyClient()
test.demo(p)

输出:

config_size=2 config_type=1

【讨论】:

  • 感谢您的帮助。我知道这行得通。但是,在我的代码中,Start() 是一个回调,从 C++ 端调用,而不是从 Python 端调用...
  • @Ben 上面编辑添加了一个 C++ 函数,该函数采用 Base* 并调用其 Start 方法。它仍然有效。如果您仍有问题,请使用minimal reproducible example 编辑您的问题。
  • 再次感谢。问题是 Start 函数是从 Nuget 包调用的,这使得创建自包含示例变得困难,我确实发现了一些有趣的东西,已添加到问题中。
  • @Ben 它在哪里被调用无关紧要,所以用另一个 C++ 调用替换 Nuget 部分,看看它是否会产生相同的错误。 尝试创建minimal reproducible example。也许你的 .i 文件或构建过程有问题
  • 感谢您的建议,但是设置一个示例,我发现了问题(见下文)
【解决方案2】:

啊,我终于弄明白了,原来Property 类在C++ 代码中位于不同的命名空间中,但不在 SWIG 接口文件中。

通过设置正确的命名空间,生成了一个代理,一切正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    相关资源
    最近更新 更多