Boost.Python - 如何通过引用返回?

时间:2009-10-15 08:31:55

标签: python boost boost-python

我正在使用Boost.Python从C ++类创建Python模块。我遇到了引用问题。

Condider以下情况我有一个类Foo,它有重载的get方法,可以按值或引用返回。

一旦我输入了签名,指定应该使用返回值很容易。但我认为应该可以使用return_value_policy返回引用。但是,使用看似合适的东西(doc); 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 :(得分:7)

在Python中,有不可变类型的概念。不可变类型的值不能更改。内置不可变类型的示例是int,float和str。

话虽如此,你不能用boost::python做你想做的事,因为Python本身不允许你改变函数返回的float的值。

您的第二个示例显示了一个解决方案,另一个示例是创建精简包装并公开:

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

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

这比更改原始C ++类更好。

答案 1 :(得分:3)

我认为你想要return internal reference。我以前用过它来做类似的事情。

修改:Latest doc

答案 2 :(得分:0)

我对Boost.Python了解不多,所以我可能会误解这个问题,在这种情况下,这完全没有用。但是这里有:

在Python中,您不能选择通过引用返回还是通过值进行选择,这种区别在Python中没有意义。我发现最容易将其视为通过引用处理的所有内容。

您只有对象,并且您拥有这些对象的名称。所以

foo = "ryiuy"

创建字符串对象“ryiuy”,然后让您引用名为“foo”的字符串对象。所以在Python中,当你传递一些东西时,你就会传递那个对象。这样没有“值”,因此您无法传递该值。但话说回来,它也是一个有效的观点,即没有引用,只有对象及其名称。

所以答案是,我猜,当你在C中获得引用时,你需要传递对引用Python的对象的引用。当你在C中得到一个值时,你需要将你从该值创建的对象的引用传递给Python。

答案 3 :(得分:0)

您确定要复制c ++对象吗?每次都会获得一个新的python对象,但它引用相同的c ++对象。你是如何确定该对象已被复制的?