[C++-sig] Boost.Python: Caching Python object instances

Doug Gregor dgregor at cs.indiana.edu
Mon Aug 7 15:59:03 CEST 2006


Hello,

I am using Boost.Python to expose the Boost Graph Library in Python.  
The vertices in the graph types are small structures that are always  
passed by value. A vertex looks something like this:

	struct Vertex {
	  int index;
	  Graph* graph;
	};

This class is exposed to python in the normal way:

	class_<vertex_descriptor>();

Now, each time that we convert a Vertex from C++ to Python,  
Boost.Python will create a new PyObject for it. This behavior has  
surprised us a few times, and contributes to some performance  
problems. So, I would like to cache the PyObject instances in the  
Graph object itself:

	class Graph {
	public:
	  std::vector<boost::python::object> py_vertices;
	};

When I add a new vertex, I want to create a Python object for it and  
store that object in the py_vertices vector. Then, when Boost.Python  
needs to convert a vertex_descriptor value "v" to a Python object,  
I'd like to return "py_vertices[v.index]" instead of creating a new  
object.

With lots of hackery, I've attained some limited success in this area.

My approach is to register a to_python_vertex for the vertex type  
with this function object:

   struct cached_vertex_object {
     static PyObject* convert(const Vertex& v) {
         PyObject* result = v.graph->py_vertices[v.index].ptr();
         Py_INCREF(result);
         return result;
     }
   };

   to_python_converter<Vertex, cached_vertex_object>();

Of course, now I have the problem of creating the  
boost::python::object values to put in the cache! Digging around in  
the source a bit, I came up with this:

   typedef class_cref_wrapper<Vertex,
                              make_instance<Vertex,  
value_holder<Vertex> > >
     Converter;

   Vertex result(this->py_vertices.size(), this);
   boost::python::object vertex_object(handle<>(Converter::convert 
(result)));
   this->py_vertices.push_back(result);

This actually does work, but I get a sharp rebuke from Boost.Python  
whenever my extension module gets loaded:

/u/dgregor/lib/python/boost/graph/__init__.py:10: RuntimeWarning: to- 
Python converter for boost::graph::python::basic_descriptor<void*,  
boost::undirectedS> already registered; second conversion method  
ignored.
   from _graph import *

I have two questions:

	1) Is there a better way to cache Python object instances with  
Boost.Python?

	2) I've filtered out those Boost.Python warnings: will they come  
back to bite me eventually?

	Cheers,
	Doug



More information about the Cplusplus-sig mailing list