[C++-sig] Re: Creating an instance of a python class derived from a C++ object from C++

David Abrahams dave at boost-consulting.com
Sat Jul 10 21:47:03 CEST 2004


Brian Hall <bhall at midwaygames.com> writes:

> Hello all,
>
> Say I have the following:
>
> class MyCppClass
> {
> public:
>   virtual int SomeFunction(void) = 0;
> };
>
> struct MyCppClassWrap : public MyCppClass
> {
>   MyCppClassWrap(PyObject *self_)
>     : self(self_)
>   {}
>   int SomeFunction(void) { return call_method<int>(self, "some_function"); }
>
>   PyObject *self;
> };
>
> int call_SomeFunction(MyCppClass &c) { return c.SomeFunction(); }
>
> BOOST_PYTHON_MODULE(MyPythonModule)
> {
>   class_<cState>("State", init<std::string>())
>     .def("value", &cState::Value)
>     .def("set_value", &cState::SetValue)
>     .def("initial_value", &cState::InitialValue)
>     .def("set_initial_value", &cState::SetInitialValue)
>     .def("name", &cState::Name)
>     .def("reset", &cState::Reset)
>     .def("iterate", &cState::Iterate)
>   ;
>   def("call_some_function", call_SomeFunction);
> };
>
> Now say I want to dynamically create an instance of a python class derived 
> from MyCppClass like so:
>
> class MyPythonClass(MyCppClass):
>   def SomeFunction(self):
>     return 42
>
> But I want to do this from C++, not Python... how would I do this?  

Use the metaclass interface:

  >>> class fu(object):pass
  ...
  >>> bases = (fu,)
  >>> attributes = { 'x' : 1, 'quack' : lambda self: 'like a duck' }
  >>> bar = object.__class__('bar', bases, attributes) # a derived class of fu
  >>> help(bar)
  Help on class bar in module __main__:

  class bar(fu)
   |  Method resolution order:
   |      bar
   |      fu
   |      __builtin__.object
   |
   |  Methods defined here:
   |
   |  lambdaself
   |
   |  ----------------------------------------------------------------------
   |  Data and other attributes defined here:
   |
   |  x = 1
   |
   |  ----------------------------------------------------------------------
   |  Data and other attributes inherited from fu:
   |
   |  __dict__ = <dictproxy object>
   |      dictionary for instance variables (if defined)
   |
   |  __weakref__ = <attribute '__weakref__' of 'fu' objects>
   |      list of weak references to the object (if defined)

  >>> bar().quack()
  'like a duck'
  >>> bar.x
  1

So,

    object py_cState; // the Python class object

    BOOST_PYTHON_MODULE(MyPythonModule)
    {
      py_cState = class_<cState>("State", init<std::string>())
      ^^^^^^^^^^^^
        .def("value", &cState::Value)
        .def("set_value", &cState::SetValue)
        .def("initial_value", &cState::InitialValue)
        .def("set_initial_value", &cState::SetInitialValue)
        .def("name", &cState::Name)
        .def("reset", &cState::Reset)
        .def("iterate", &cState::Iterate)
      ;
      def("call_some_function", call_SomeFunction);
    };
    
    char const* quack(object self) { return "like a duck"; }

    // returns a new class
    object make_bar
    {
        object bases = make_tuple(py_cState);
        dict attributes;
        attributes['x'] = 1;
        attributes['quack'] = quack;

        return py_cState.attr("__class__")("bar", bases, attributes);
    };

> Basically 
> I want to be able to define new Python derived types of MyCppClass at runtime 
> on the fly, and redefine them at will.  Say for instance the user of the 
> application typed in the above declaration of MyPythonClass... and then later, 
> updated that definition to return 43 instead, I want to be able to redefine 
> the code for the class... if I did that, would I have to destroy the old 
> instance and create a new one?  Any ideas?

You can always replace the class' methods one-at-a-time.

-- 
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com




More information about the Cplusplus-sig mailing list