2009-10-15 15 views
10

Ich verwende Boost.Python, um Python-Module aus C++ - Klassen zu erstellen. Und ich stieß auf ein Problem mit Referenzen.Boost.Python - Wie man als Referenz zurückkommt?

Condider folgenden Fall, in dem ich eine Klasse Foo mit überladenen get-Methoden haben, die entweder Rückkehr nach Wert oder Verweis.

angeben, dass die Rückkehr nach Wert verwendet werden soll, war einfach, wenn ich eine Signatur typedefed. Aber ich denke, es sollte möglich sein, eine Referenz auch mit einem return_value_policy zurückzugeben. Allerdings mit dem, was angemessen erschien (doc); return_value_policy<reference_existing_object> schien nicht zu funktionieren.

Habe ich missverstanden, was es tut?

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

Hinweis: Ich weiß, dass es gefährlich sein könnte vorhandenes Objekt ohne Lebenszeit Verwaltung zu verweisen.

Update:
Es sieht aus wie es für Objekte, nicht aber grundlegende Datentypen funktioniert.
Nehmen Sie dieses überarbeitete Beispiel:

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

, die in einem Test das erwartete Ergebnis gab:

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

Antwort

7

In Python gibt es das Konzept der unveränderlichen Typen. Ein unveränderlicher Typ kann nicht geändert werden. Beispiele für integrierte unveränderliche Typen sind int, float und str.

Nachdem Sie das gesagt haben, können Sie mit nicht tun, was Sie wollen, weil Python selbst Ihnen nicht erlaubt, den Wert des float zu ändern, der von der Funktion zurückgegeben wird.

Ihr zweites Beispiel zeigt eine Lösung, eine andere wäre Dünn Wrapper zu erstellen und das Aussetzen:

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

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

, die eine bessere Lösung ist als mit der ursprünglichen C++ Klasse zu ändern.

0

Ich weiß nicht viel über Boost.Python, ich kann die Frage so falsch verstehen, in denen Fall, das ist völlig nicht hilfreich. Aber hier geht:

In Python Sie als Referenz oder als Wert zwischen Rückkehr nicht wählen können, ist die Unterscheidung keinen Sinn in Python machen. Ich finde es am einfachsten, es als alles zu betrachten, was durch Bezugnahme gehandhabt wird.

Sie haben nur Objekte, und Sie haben Namen für diese Objekte. So

foo = "ryiuy" 

Erzeugt das String-Objekt „ryiuy“ und dann können Sie in diesem String-Objekt beziehen sich mit dem Namen „foo“. Wenn Sie in Python etwas passieren lassen, erhalten Sie dieses Objekt. Es gibt keine "Werte" als solche, so dass Sie den Wert nicht übergeben können. Aber es ist auch ein gültiger Standpunkt, dass es keine Referenzen gibt, nur Objekte und ihre Namen.

Die Antwort ist also, glaube ich, ist, dass, wenn Sie einen Verweis in C erhalten, müssen Sie einen Verweis auf das Objekt zu übergeben, die Verweise in Python verweisen. Und wenn Sie einen Wert in C erhalten, müssen Sie einen Verweis auf das von Ihnen erstellte Objekt in Python übergeben.

+0

Ja, ich weiß, alles ist Referenzen in Python. Wenn ich eine Python-Methode mit Boost.Python erstelle, die "nach Wert" zurückgibt, wird eine Kopie dieses Typs zurückgegeben. Ich möchte * nicht * kopieren, sondern stattdessen einen Verweis auf dieselbe Instanz erstellen. – mandrake

0

Sind Sie sicher, dass das C++ - Objekt kopiert wird? Sie erhalten jedes Mal ein neues Python-Objekt, das auf dasselbe C++ - Objekt verweist. Wie bestimmen Sie, dass das Objekt kopiert wurde?

+0

Es kompiliert nicht, wenn ich versuche, Referenzen zu verwenden. Wie zu bestimmen, ob es Referenzen oder Kopien ist einfach. Erstellen Sie zwei Referenzen auf das, was Sie für das selbe Objekt halten, modifizieren Sie eines und sehen Sie, ob die Änderungen in dem anderen Objekt erscheinen. (mit id (obj) würde nicht funktionieren). – mandrake

+0

Ja, wollte fragen, ob du ID() benutzt hast. Was ist der Kompilierungsfehler? – Ben

+0

Es ist ein boost :: STATIC_ASSERTION_FAILURE, das anzeigt, dass etwas, was ich mache, entweder nicht unterstützt wird oder illegal ist. Ich weiß einfach nicht was. – mandrake

2

Ich glaube, Sie return internal reference stattdessen wollen. Ich habe es schon früher benutzt, um etwas Ähnliches zu machen.

Edit: Latest doc

+0

Es ist der gleiche Deal. Es funktioniert mit Objekten, aber nicht mit grundlegenden Datentypen. – mandrake

+0

der Link zur Dokumentation ist für Version 1.38, die sehr alt ist von diesem Kommentar (1.61 ist aktuell) – ofloveandhate

Verwandte Themen