adding methods on the fly

Alex Martelli aleax at aleax.it
Mon Jul 8 17:41:55 EDT 2002


Renzo Tomaselli wrote:
        ...
> I mean a function declaration in a string. In short, what I miss is a
> way to transform it into a callable object to be added to a class.
> Whether such class is just a wrapper on my C++ object or a Python
> derived class depends on issue below.
> I'm lost here between PyRun_String and PyCompile_String, which seem
> the only places where I can start from code strings to add methods on

Py_CompileString (careful about underscore placement!-) won't let you
easily build a function (or unbound-method) object, which is what you
need (though you can get there eventually, but it's a long way 'round).

With PyRun_String, passing an appropriate, initially empty dict as the
locals argument, you can execute a statement held in a string such as
"def somename(self, whatever): return whatever", and find in said locals
dict under key "somename" the resulting function object.

However, you can't add attributes to a normally-coded C (or C++)
type -- that's another issue yet.


>> Yes, as long as that C-coded type IS specifically coded as to support
>> being inherited from.  Once again, it all depends on how you code at
>> the C level.
> 
> Could you please explain this topic a little further ? How do we
> enable a C type to be inherited from by a Python class ?

You need a few things, starting with Py_TPFLAGS_BASETYPE among
the flags, but not ending there -- allocation / newing / initialization are
the key part.  For perspective,  I would suggest you study subclassable
built-in objects, such as Objects/tupleobject.c -- tuple_new and
tuple_subtype_new are the key spots.  Then, examine the alternative
strategy in Objects/listobject.c -- since list objects are mutable, they
need no special alloc or new, but can handle all needs in list_init and
the functions it, in turn, calls.  Objects/dictobject.c shows yet another
strategy, and Objects/fileobject.c a pretty similar one.  Offhand, I
suspect listobject's strategy would be sufficient for your purposes, but,
if not, the one used by dicts and file objects will most likely be.


>> One way to avoid depending on how the C-level code is written is to
>> use wrapping and automatic delegation in your Python class -- that
        ...
> Ok, got it. The overall issue is dealt with in the opposite way I'm
> interested in: almost all involved discussions on this list handle
> about estending Python by C/C++ while I need to extend C++ by Python.

You're not going to be able to add to C++ classes methods on the
fly in ways that let other C++ code call the new methods, anyway.

That being a given -- i.e., given that the client-code of your
extended objects is going to be Python, anyway -- why not take
the easy way out, and have said extensible objects be a Python
shell around a C++ core?  A thin Python shell, which you can add
with a small effort by inheritance in Python 2.2, or more easily and
portably (with a loss of performance) by automatic delegation,
lets you extend to your heart's content.  So, why not...?

> And possibly by adding just functions (methods), no extra class stuff
> or modules.

Oh, we can do that, too -- at ten times the effort, and without any
benefits whatsoever, but, hey, one thing I learned as a freelance is
that, when the customer insists after you've explained that, it's best
to accept the money the customer is so insistent to push into your
hands (I charge by the hour, of course).  This way you get the extra
of saying "see, I had told you that" when the problems do develop:-)

> Thanks for any suggestion,

Let's see, I'm going to spend a week's vacation in Trentino anyway,
so, if you need further help implementing things your way rather than
in the easy way, I'm willing to charge you just my hourly rate -- no
extra for the trip to/from Bologna.  Can't get much fairer than that...

If you want a serious suggestion, though, it's to re-think the idea that
you *need* to have the extensible object itself be the one that is
implemented in C++, rather than a thin Python wrapper around it.  It
CAN be done, but, what benefits do you propose to obtain from such
a contrarian approach...?  Will they repay substantial additional effort...?

Another possibility is to look at Boost Python, if the schedule for their
new release 2 (supporting Python 2.2 fully) is compatible with your
timing constraints.  I'm not privvy to the details of the new release,
whose webpages claim to have been revised on Nov 5, 2002 (!),
but in the previous v1 the Boost guys had basically implemented a
custom metaclass (...and by the hard and complicated rules that
were needed in older Pythons, no less...) that should make it easier
to implement your exact specs, once one understands it well enough
to know what to tweak.  Boost Python can surely be recommended
for the dyed-in-the-wool, hard and pure C++ hacker.  I used to
qualify (and I'm still a C++ MVP for Brainbench), but I've since seen
the light and left an otherwise-excellent but deeply C++-centered
job in order to do Python full time instead.  Of course, just like one
who used to smoke heavily then quit, this may leave me, at times,
slightly intolerant of typical C++ complications ... :-).


Alex




More information about the Python-list mailing list