1 // Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost 2 // Software License, Version 1.0. (See accompanying 3 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 4 5 /* 6 This example shows how to make an Extension Class "pickleable". 7 8 The world class below contains member data (secret_number) that 9 cannot be restored by any of the constructors. Therefore it is 10 necessary to provide the __getstate__/__setstate__ pair of pickle 11 interface methods. 12 13 The object's __dict__ is included in the result of __getstate__. 14 This requires more code (compare with pickle2.cpp), but is 15 unavoidable if the object's __dict__ is not always empty. 16 17 For more information refer to boost/libs/python/doc/pickle.html. 18 */ 19 20 #include <boost/python/module.hpp> 21 #include <boost/python/def.hpp> 22 #include <boost/python/class.hpp> 23 #include <boost/python/tuple.hpp> 24 #include <boost/python/dict.hpp> 25 #include <boost/python/extract.hpp> 26 #include <boost/python/back_reference.hpp> 27 28 namespace boost_python_test { 29 30 // A friendly class. 31 class world 32 { 33 public: world(const std::string & _country)34 world(const std::string& _country) : secret_number(0) { 35 this->country = _country; 36 } greet() const37 std::string greet() const { return "Hello from " + country + "!"; } get_country() const38 std::string get_country() const { return country; } set_secret_number(int number)39 void set_secret_number(int number) { secret_number = number; } get_secret_number() const40 int get_secret_number() const { return secret_number; } 41 private: 42 std::string country; 43 int secret_number; 44 }; 45 46 struct world_pickle_suite : boost::python::pickle_suite 47 { 48 static 49 boost::python::tuple getinitargsboost_python_test::world_pickle_suite50 getinitargs(const world& w) 51 { 52 return boost::python::make_tuple(w.get_country()); 53 } 54 55 static 56 boost::python::tuple getstateboost_python_test::world_pickle_suite57 getstate(boost::python::object w_obj) 58 { 59 world const& w = boost::python::extract<world const&>(w_obj)(); 60 61 return boost::python::make_tuple( 62 w_obj.attr("__dict__"), 63 w.get_secret_number()); 64 } 65 66 static 67 void setstateboost_python_test::world_pickle_suite68 setstate(boost::python::object w_obj, boost::python::tuple state) 69 { 70 using namespace boost::python; 71 world& w = extract<world&>(w_obj)(); 72 73 if (len(state) != 2) 74 { 75 PyErr_SetObject(PyExc_ValueError, 76 ("expected 2-item tuple in call to __setstate__; got %s" 77 % state).ptr() 78 ); 79 throw_error_already_set(); 80 } 81 82 // restore the object's __dict__ 83 dict d = extract<dict>(w_obj.attr("__dict__"))(); 84 d.update(state[0]); 85 86 // restore the internal state of the C++ object 87 long number = extract<long>(state[1]); 88 if (number != 42) 89 w.set_secret_number(number); 90 } 91 getstate_manages_dictboost_python_test::world_pickle_suite92 static bool getstate_manages_dict() { return true; } 93 }; 94 95 } 96 BOOST_PYTHON_MODULE(pickle3_ext)97 BOOST_PYTHON_MODULE(pickle3_ext) 98 { 99 using namespace boost_python_test; 100 boost::python::class_<world>( 101 "world", boost::python::init<const std::string&>()) 102 .def("greet", &world::greet) 103 .def("get_secret_number", &world::get_secret_number) 104 .def("set_secret_number", &world::set_secret_number) 105 .def_pickle(world_pickle_suite()) 106 ; 107 } 108