11

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

考虑以下情况,其中我有一个类 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

4 回答 4

7

在 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++ 类更好的解决方案。

于 2010-01-22T18:33:31.603 回答
3

我认为您想要返回内部参考。我以前用它来做类似的事情。

编辑:最新文档

于 2010-01-05T20:49:08.177 回答
0

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

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

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

foo = "ryiuy"

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

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

于 2009-10-15T09:04:48.930 回答
0

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

于 2009-10-15T10:07:14.140 回答