[C++-sig] returning PyObject * (unmodified) from embedded python back to c++

Ambrose Kofi Laing aklaing at gmail.com
Fri Mar 14 01:54:52 CET 2008


Hi,

I sent this email earlier and I'm not sure if it came through (I was
just getting subscribed).  I'm new to boost::python, and I need to
write a program that defines an abstract base class in C++, and a
derived class in Python.  Then I want to instantiate the derived class
in python and store its address in a C++ variable of type pointer to
the base type and call python methods in the derived type
polymorphically from C++.  All of that works.  The remaining problem
is how to let the python function return arbitrary python objects to
C++, and have C++ hold a pointer to the arbitrary returned result.
Below is my code so far, it isn't working as written (but when I
change all the 'PyObject *' to C++ type string and make other
appropriate changes in the python file, it works for returning string
types.  Can anyone give me an idea what changes are required in the
code to do what I need?   Any  pointers would be very much appreciated.

Thanks,

Ambrose

The two files are included below:

------ mymodule.cpp ------------------------------------------------


#include <iostream>

#include <fstream>
#include <string>

using namespace std;

#include <boost/python.hpp>
using namespace boost::python;

struct Base
{
  Base() { s = Py_None; }
  Base(PyObject *input){ s = input; }
  virtual ~Base() {}
  virtual PyObject *run() { return s; }
private:
  PyObject *s;
};

struct BaseWrap : Base, wrapper<Base>
{
  BaseWrap() : Base() {}
  BaseWrap(PyObject *input) : Base(input) {}

  PyObject *run() {
    if (override run = this->get_override("run"))
      return run();
    return Base::run();
  }

  PyObject *default_run() {
    return this->Base::run();
  }
};

typedef boost::shared_ptr<Base> BasePtr;

BasePtr g(new Base);

BasePtr get_g() {
  return g;
}

BasePtr set_g(BasePtr input_g) {
  BasePtr tmp;
  tmp = g;
  g = input_g;
  return tmp;
}

PyObject *run_g() {
  PyObject *tmp;
  tmp = g->run();
  return tmp;
}

BOOST_PYTHON_MODULE(mymodule) {

  def("set_g", set_g);
  def("get_g", get_g);
  def("run_g", run_g);

  class_<BaseWrap, boost::noncopyable>("Base", init<>())
    .def(init<PyObject *>())
    .def("run", &Base::run, &BaseWrap::default_run)
  ;

  register_ptr_to_python< BasePtr >();

}

----- test.py----------------------------------------------------------------------------------------------------
#!/usr/bin/env python

from mymodule import *

class DerivedS( Base ):
    def run( self ):
        x = Base.run( self )
        return x+x

class DerivedM( Base ):

    def __init__( self ):
        import random
        x = random.randint(0,4)
        if x == 0:
            self.x = 1 # int
        elif x == 1:
            self.x = 1.0
        elif x == 2:
            self.x = 'string'
        elif x == 3:
            self.x = ['array']
        elif x == 4:
            self.x = ('tuple')

    def run( self ):
        return self.x + self.x # defined for all 5 types above

# minimal set of tests:

b1 = Base()
set_g(b1)
x = b1.run()  # test from python should print nothing
y = run_g()   # test call from C++ should print nothing
if x is None: print 'x is None'
if y is None: print 'y is None'

b2 = Base('init_str')
ib1 = set_g(b2) # want something identical to b1
b2.run()        # want 'init_str'
run_g()         # want 'init_str'

ds = DerivedS('derived')
ib2 = set_g(ds) # want something identical to b2
ds.run()        # want 'derivedderived'
run_g()         # want 'derivedderived'

dm = DerivedM()
ids = set_g(dm) # want something identical to ds
dm.run()        # want one of the values
    # 2, 2.0, 'stringstring', ['array','array'], ('tuple','tuple')
run_g()         # same output as previous
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20080313/354c8365/attachment.htm>


More information about the Cplusplus-sig mailing list