[C++-SIG] Automatic Python/C++ Wrapper

Patrick Miller patmiller at llnl.gov
Thu Mar 19 17:21:00 CET 1998


> - keep the entire wrapping tool in just 3 header files (no library
>   or code generator required)
> - keep the C++ code essentially independent of Python (no inheritance
>   from PyObject or similar required)

At LLNL, we are using a home grown "bridge language"
to glue the two pieces together.  We too want to 
keep the C++ looking and acting like C++, but
have the python looking and acting like python.

Here's what we do in the header file (your class with some
additions to show other features)

  class Foo
  {
    public:
      Foo();
      Foo(int);
      virtual ~Foo();
      virtual int foo_method(int, int);
      int getX();
      void setX(int);
  };


  class Bar : public Foo
  { public: Bar(); Bar(int,int); int getY(); void setY(int); };

  class FooBar {
    public: 
    FooBar(Foo&,Bar&);
  };

/*#!python
  wrapper('Foo',
    '#include "Foo.h"',
    ctor(),
    ctor(int),
    mfunc('void','foo_method(int,int)'),
    mfunc('void','foo_method(int,int,char*)'),
    attr('int','x','@->getX()','@->setX($1)',doc='an x attr'),
    doc='A foo is half of a foobar'),
  wrapper('Bar',
    inherit('Foo'),
    ctor(),
    ctor('int','int'),
    attr('int','y','@->getY()','@->setY($1)'),
    doc='A bar is half of a foobar'),
  ),
  wrapper('FooBar',
    ctor('Foo&','Bar&')
  )
*/

We run our PYFFLE script over it to create method.cc and a foomodule.c
file for the extensions.

>>> from foo import Foo,Bar,FooBar # These are FUNCTIONS that create
>>> # the new types
>>> f = foo()
>>> print f # The default string method can be overriden
<foo 0xdeadbeef>
>>> print f.x
0
>>> f.x = 3
>>> f.foo_method()
ValueError: needs 2 or 3 arguments
>>> f.foo_method(1,2)
I'm in foo_method
>>> b = Bar()
>>> b.foo_method(1,2)
I'm in foo_method
>>> fb = FooBar(f,b)

-----------------------------------------------
PYFFLE has other features too like building python
sequence types (add a __len__ mfunc and a
seq('kfsdkf','[int]', <get code>, <set code>) line to any
PYFFLE wrapper),

We also build and use a lot of STL containers, so we have
support for vector<T> and list<T>.

PYFFLE also will "build on the fly" to support type coercion.
For instance, we have a class "Triplet" which is a triple
of doubles.  However, we don't want users to have to do things
like

wrapper('Take2Triples',ctor('Triplet&','Triplet&'),....)

>>> F = Take2Triples(Triplet(1,2,3),Triplet(1,2,3))

when

>>> F = Take2Triples((1,2,3),(1,2,3)) reads so much better!

So we have added a "contstructable" flag to PYFFLE that
allows either the "correct" type to be at an argument
site OR something from which the correct type can be built.

This is real nice for things that take vector<int> arguments
because we can arrange to allow ANY python sequence (something
that supports integer __getitem__ and __len__) to be used
directly

>>> class myseq:
      def __init__(self,x): pass
      def __len__(self): return 3
      def __getitem__(self,i): return 5
>>> v = F([1,2,3,4])
>>> w = F(range(0,100))
>>> z = F(myseq('abc'))

instead of

>>> v = F(vector_of_int(1,2,3,4))
>>> w = F(vector_of_int(tuple(range(0,100))) 
>>> ms = myseq('abc')
>>> z = F(vector_of_int(lambda x,i: x[i],ms,range(0,len(ms)))


Is there general interest in this?  I am hoping to clean it up
enough to put on the Starship


Pat




More information about the Cplusplus-sig mailing list