Boost.Python - 如何按引用返回?

11 投票
4 回答
15714 浏览
提问于 2025-04-15 15:05

我正在使用Boost.Python把C++类转换成Python模块。遇到了一些关于引用的问题。

考虑一下我有一个叫Foo的类,它有重载的get方法,可以返回值或者引用。

一旦我定义了一个类型别名,指定返回值的方式就变得简单了。但是我觉得应该也可以通过使用一个 return_value_policy 来返回引用。不过,使用我认为合适的方式(文档); return_value_policy<reference_existing_object> 似乎没有奏效。

我是不是误解了它的作用?

struct Foo {
    Foo(float x) { _x = x; }
    float& get() { return _x; }
    float  get() const { return _x; }
private:
    float _x;
};

// Wrapper code
BOOST_PYTHON_MODULE(my_module)
{
    using namespace boost::python;
    typedef float (Foo::*get_by_value)() const;
    typedef float& (Foo::*get_by_ref)();

    class_<Foo>("Foo", init<float>())
        .def("get", get_by_value(&Foo::get))
        .def("get_ref", get_by_ref(&Foo::get),
            return_value_policy<reference_existing_object>())//Doesn't work
        ;
}

注意:我知道在没有管理生命周期的情况下引用现有对象可能是危险的。

更新:
看起来它对对象有效,但对基本数据类型无效。
下面是这个修订后的例子:

struct Foo {
    Foo(float x) { _x = x; }
    float& get() { return _x; }
    float  get() const { return _x; }
    void set( float f ){ _x = f;}
    Foo& self(){return *this;}
private:
    float _x;
};

// Wrapper code
using namespace boost::python;
BOOST_PYTHON_MODULE(my_module)
{
    typedef float (Foo::*get_by_value)() const;

    class_<Foo>("Foo", init<float>())
        .def("get", get_by_value(&Foo::get))
        .def("get_self", &Foo::self,
            return_value_policy<reference_existing_object>())
        .def("set", &Foo::set);
        ;
}

在测试中得到了预期的结果:

>>> foo1 = Foo(123)
>>> foo1.get()
123.0
>>> foo2 = foo1.get_self()
>>> foo2.set(1)
>>> foo1.get()
1.0
>>> id(foo1) == id(foo2)
False

4 个回答

0

你确定这个C++对象真的被复制了吗?每次你会得到一个新的Python对象,但它其实是指向同一个C++对象的。你是怎么判断这个对象被复制了呢?

4

我觉得你可能想要的是返回内部引用。我之前用过这个,做过类似的事情。

编辑:最新文档

7

在Python中,有一个叫做不可变类型的概念。不可变类型的值是不能被改变的。比如,Python内置的不可变类型有整数(int)、浮点数(float)和字符串(str)。

也就是说,你不能随心所欲地使用boost::python,因为Python本身不允许你改变函数返回的浮点数的值。

你第二个例子展示了一种解决方案,另外一种方法是创建一些简单的包装器并将其暴露出来:

void Foo_set_x(Foo& self, float value) {
    self.get() = value;
}

class_<Foo>("Foo", init<float>())
    ...
    .def("set", &Foo_set_x);
;

这比直接修改原来的C++类要好。

撰写回答