2009-10-15 91 views
10

我使用Boost.Python从C++类创建Python模块。我遇到了一个引用问题。Boost.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 

回答

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

0

我不知道很多关于Boost.Python的,所以我可能误解了问题,在其中这种情况完全没有帮助。但是这里有:

在Python中,您不能选择通过引用还是通过值返回,但在Python中这种区别没有意义。我觉得最简单的办法就是将所有事情都通过参考来处理。

你只有对象,并且你有这些对象的名字。因此,

foo = "ryiuy" 

创建字符串对象“ryiuy”,然后让您引用该名称为“foo”的字符串对象。所以在Python中,当你传递一些东西时,你会传递那个对象。没有像这样的“价值”,所以你不能通过价值。但是,再次,也有一个有效的观点,即没有引用,只是对象和它们的名字。

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

+0

是的,我知道一切都是Python中的引用。当我用Boost.Python创建一个“按值”返回的python方法时,它会返回该类型的副本。我想要做的是*不*复制,而是创建一个对同一个实例的引用。 – mandrake 2009-10-15 10:01:43

0

你确定C++对象被复制吗?每次你将得到一个新的python对象,但是引用相同的C++对象。你如何确定该对象已被复制?

+0

当我尝试使用引用时,它不会编译。 至于如何确定它的参考或副本很容易。创建两个你认为是同一个对象的引用,修改一个,看看这些更改是否出现在另一个对象中。 (使用id(obj)不起作用)。 – mandrake 2009-10-15 10:20:05

+0

是的,要求检查你没有使用id()。什么是编译错误? – Ben 2009-10-15 10:21:34

+0

这是一个boost :: STATIC_ASSERTION_FAILURE,它表明我所做的事情是不受支持或非法的。我只是不知道是什么。 – mandrake 2009-10-15 13:26:56

2

我想你想要return internal reference来代替。我以前用它来做类似的事情。

编辑:Latest doc

+0

这是一样的交易。它适用于对象,但不适用于基本数据类型。 – mandrake 2010-01-07 08:46:10

+0

指向文档的链接适用于版本1.38,这是非常旧的评论(1.61是最新的) – ofloveandhate 2016-08-30 14:07:43