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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1571054/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 22:36:36  来源:igfitidea点击:

Boost.Python - How to return by reference?

pythonboostboost-python

提问by mandrake

I'm using Boost.Python to create Python modules from C++ classes. And I ran into a problem with references.

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

Condider the following case where I have a class Foo with overloaded get methods that can either return by value or reference.

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

Specifying that the return by value should be used was easy once I typedefed a signature. But I think it should be possible return a reference as well by using a return_value_policy. However, using what seemed appropriate (doc); return_value_policy<reference_existing_object>did not seem to work.

一旦我键入了签名,指定应该使用按值返回就很容易了。但我认为也应该可以通过使用 return_value_policy. 但是,使用似乎合适的(doc);return_value_policy<reference_existing_object>似乎没有用。

Have I misunderstood what it does?

我误解了它的作用吗?

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
        ;
}

Note: I know it could be dangerous to reference existing object without life-time managing.

注意:我知道在没有终身管理的情况下引用现有对象可能很危险。

Update:
It looks like it works for objects but not basic data types.
Take this revised example:

更新:
看起来它适用于对象,但不适用于基本数据类型。
以这个修改过的例子为例:

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);
        ;
}

Which in a test gave the expected result:

在测试中给出了预期的结果:

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

采纳答案by Bruno Oliveira

In Python, there's the concept of immutable types. An immutable type can't have its value changed. Examples of built-in immutable types are int, float and str.

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

Having said that, you can't do what you want with boost::python, because Python itself does not allow you to change the value of the float returned by the function.

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

Your second example shows one solution, another would be to create thin-wrappers and exposing that:

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

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

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

Which is a better solution than having to change the original C++ class.

这是比必须更改原始 C++ 类更好的解决方案。

回答by Charles

I think you want return internal referenceinstead. I have used it before to do something similar.

我认为你想要返回内部引用。我以前用它做过类似的事情。

Edit: Latest doc

编辑:最新文档

回答by Lennart Regebro

I don't know much about Boost.Python, so I may misunderstand the question, in which case this is completely unhelpful. But here goes:

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

In Python you can't choose between returning by reference or by value, the distinction doesn't make sense in Python. I find it's easiest to think of it as everything being handled by reference.

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

You just have objects, and you have names for those objects. So

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

foo = "ryiuy"

Creates the string object "ryiuy" and then lets you refer to that string object with the name "foo". So in Python, when you get passed something, you get passed that object. There is no "values" as such, so you can't pass the value. But then again, it's also a valid viewpoint that there aren't references either, just objects and their names.

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

So the answer is, I guess, is that when you get a reference in C, you need to pass a reference to the object that reference references into Python. And when you get a value in C, you need to pass a reference to the object that you create from that value into Python.

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

回答by Ben

Are you sure that the c++ object is being copied? You will get a new python object each time but which references the same c++ object. How are you determining that the object has been copied?

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