2009-10-15 3 views
10

저는 Boost.Python을 사용하여 C++ 클래스에서 파이썬 모듈을 작성하고 있습니다. 그리고 나는 참고 문헌에 문제가 생겼다.Boost.Python - 참조로 돌아 오는 방법?

다음 경우에 값 또는 참조로 반환 할 수있는 오버로드 된 get 메서드가있는 Foo 클래스가 있습니다.

서명을 typedef 한 후에 값으로 반환을 사용해야한다고 지정하는 것이 쉬웠습니다. 하지만 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

, 불변의 유형의 개념이있다. 불변 형은 값을 변경할 수 없습니다. 내장형 불변 형의 예는 int, float 및 str입니다.

그렇다면, boost::python으로 원하는 것을 할 수 없다는 것입니다. 파이썬 자체가 함수에서 반환 된 float 값을 변경할 수 없기 때문입니다.

두 번째 예는 하나 개의 솔루션을 보여주고, 또 다른 얇은 래퍼를 생성하고 그 노출 것 :

++ 클래스 원래 C를 변경하는 것보다 더 나은 솔루션입니다
void Foo_set_x(Foo& self, float value) { 
    self.get() = value; 
} 

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

.

0

내가 Boost.Python에 대해 잘 모르는, 그래서 질문을 오해 할 수있다을하는 이 경우는 전혀 도움이되지 않습니다. 그러나 여기에 간다 :

파이썬에서는 참조 나 값으로 반환 할 것인지 선택할 수 없다. 구별은 파이썬에서는 의미가 없다. 나는 참조로 처리되는 모든 것을 생각하는 것이 가장 쉬운 방법이라는 것을 알았습니다.

개체가 있고 그 개체의 이름이 있습니다. 따라서

foo = "ryiuy" 

"ryiuy"문자열 개체를 만든 다음 해당 문자열 개체를 "foo"이름으로 참조 할 수있게합니다. 그래서 파이썬에서, 당신이 무언가를 통과하게되면, 당신은 그 객체를 통과하게됩니다. "값"이 없으므로 값을 전달할 수 없습니다. 그러나 다시 한번, 참조도없고 단지 객체와 그 이름도 없다는 것도 유효한 관점입니다.

답은 C에서 참조를 얻으면 참조를 참조하는 객체에 대한 참조를 Python으로 전달해야한다는 것입니다. 그리고 C에서 값을 얻을 때, 그 값에서 생성 한 객체에 대한 참조를 Python에 전달해야합니다.

+0

그래, 나는 모든 것이 파이썬에서 참조된다는 것을 알고있다. Boost.Python으로 "값으로"반환하는 파이썬 메소드를 만들면 그 타입의 복사본을 반환합니다. 내가하고 싶은 것은 * 복사하지 않고 같은 인스턴스에 대한 참조를 만드는 것입니다. – mandrake

0

C++ 개체가 복사되고 있습니까? 매번 새로운 파이썬 객체를 갖지만 동일한 C++ 객체를 참조합니다. 그 대상이 복사되었다고 어떻게 결정합니까?

+0

참조를 사용하려고하면 컴파일되지 않습니다. 참조 또는 사본인지 확인하는 방법은 쉽습니다. 동일한 객체라고 생각하는 것에 대한 두 가지 참조를 만들고, 하나를 수정하고 변경 사항이 다른 객체에 표시되는지 확인합니다. (id (obj)를 사용하면 작동하지 않습니다). – mandrake

+0

예, id()를 사용하고 있지 않은지 확인해달라고 요청했습니다. 컴파일 오류가 뭐죠? – Ben

+0

그것은 boost :: STATIC_ASSERTION_FAILURE입니다. 이는 내가하는 일이 지원되지 않거나 불법임을 나타냅니다. 나는 단지 무엇을 모른다. – mandrake

2

대신 return internal reference이 필요하다고 생각합니다. 나는 비슷한 것을하기 전에 그것을 사용했다.

편집 : Latest doc 파이썬에서

+0

동일한 거래입니다. 객체에는 적용되지만 기본 데이터 유형에는 적용되지 않습니다. – mandrake

+0

설명서 링크는 버전 1.38입니다.이 주석의 현재 시점은 매우 오래된 버전입니다 (1.61은 현재 버전 임). – ofloveandhate