2

I'm using Boost.Python to expose an array of objects within another class:

class Thing {
  int i; // and of course other stuff
};

class Container {
  Thing *things[128];
  int n_things;
}

I'd like to provide to python a read-only list interface to the Things. I have something like this in my boost.python extension source code:

static bp::list EXTget_things(Container &c)
{
  bp::list thing_list;
  for (int i = 0; i < c.n_things; i++) {
    thing_list.append(c.things[i]);
  }
  return thing_list;
}

I also have the (unusual?) constraint that I can't copy the Thing objects. They don't have a working copy constructor, and I can't really change that. I'd like to just return a python list containing the addresses of the original objects, and correspondingly ensure that python doesn't free the originals when it frees the list.

How can I do that? (Or can it be done?) I recognize it could cause lifetime problems if the Container goes out of scope in python, but some other python code still tries to use the param_list (since it has pointers into the Collection object), but I'm willing to work with that restriction.

0

1 Answer 1

2

One approach is to expose both classes:

class_<Thing>("thing")
    .def_readwrite("i", &Thing::i)
;

class_<Container>("container")
    .def_readwrite("n_things", &Container::n_things)
;

and then create a method that returns a reference to the Thing:

Thing& get_thing(Container& c, size_t index)
{
    return *c.things[index];
}

finally, you should expose this function:

def("get_thing", get_thing, return_value_policy<reference_existing_object>());

and than you can iterate over it:

c = mylib.container()
for i in xrange(c.n_things):
    thing = get_thing(c, i)
    thing.i = <INT_VALUE>
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, but I'm hoping for something more pythonic with a list interface.
@GaryO OK, but notice that you can change it into a python list very easily: l = [get_thing(c, i) for i in xrange(c.n_things)]
I tried this, and it basically works, but if I try get_thing(c, i)==get_thing(c, i) it returns False. Shouldn't it be returning a reference to the existing object and thus return True?
@GaryO it's because they aren't the same object, boost::python uses a trick to return the reference to the object, boost.org/doc/libs/1_55_0/libs/python/doc/v2/… (see the explanation and take a look into the last example)
In order to compare the objects, you should implement the operator eq, as pointed out here [stackoverflow.com/questions/10612218/… by @grivescorbett. (but you should compare two pointers instead of a shared_ptr and a pointer).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.