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

Ambrose Kofi Laing aklaing at gmail.com
Thu Mar 13 11:01:30 CET 2008


Hi all,

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 ?

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/51b52e06/attachment.htm>


More information about the Cplusplus-sig mailing list