Adding "proxy" functions to a type

Iker Arizmendi iker at research.att.com
Tue May 17 13:34:29 EDT 2005


Hello all.

Is there a convenient scheme within a C extension to add
methods to a type in such a way as to allow me to
transparently add a "proxy" around them? For example:

     typedef PyObject* (*PyMethodCall)(PyObject*, PyObject*);

     PyObject* middleMan(PyObject* self, PyObject* args) {
         printf("Before call to wrapped funct\n");
         PyMethodCall actualFunc = getRealFunction(...);
         PyObject* retval = actualFunc(self, args);
         printf("After call to wrapped func\n");
         return retval;
     }

     void addMethod(PyTypeObject* t, PyMethodCall* m,
                    char* name, char* doc) {
         // code to forward calls to "middleMan" while putting the
         // pointer to "m" somewhere convenient
         ...
     }

My current solution is cumbersome and involves adding a
special field to the PyObject associated with my type, a
custom tp_getattro function and the "middleMan" function:

     struct MyPyObj {
         PyObject_HEAD
         PyMethodCall realfunc;
     };

     // when adding the method def for "m" instead of pointing it to
     // the given function, I point it to the middle man and save
     // the "m" function somewhere I can find it later.
     void addMethod(PyTypeObject* t, PyMethodCall m,
                    char* name, char* doc) {

         PyMethodDef* def = allocPyMethodDef(t, name);
         def->ml_name = name;
         def->ml_doc = doc;
         def->ml_meth = middleMan;
         def->ml_flags = METH_VARARGS;

         saveTargetFunction(name, m);
         // note I add these here so that documentation is
         // available within the interpreter
         PyObject* methobj = PyDescr_NewMethod(t, def);
         PyDict_SetItemString(t->tp_dict, def->ml_name, methobj);
         Py_DECREF(methobj);
     }

     // when the interpreter does a lookup on an instance of my
     // type I set the "realfunc" member of my PyObject and return
     // a bound method (which will call into middleMan).
     PyObject* customGetaAttro(PyObject* self, PyObject* name) {
         MyPyObj* rself = (MyPyObj*)self;
         rself->realfunc = findSavedTargetFunc(name);
         PyMethodDef* mdef = getMethodDef(self->ob_type, name);
         return PyCFunction_New(def, self);
     }

     // finally, when the middle man is called it extracts the "real"
     // function from self and calls that.
     PyObject* middleMan(PyObject* self, PyObject* args) {
         MyPyObj* rself = (MyPyObj*)(self);
         printf("pre call\n");
         PyObject* rv = rself->realfunc(rself->obj, args);
         printf("post call\n");
         rself->realfunc = 0;
         return rv;
     }

The problem here is that this doesn't work for static functions which
lack a self argument, or for module level functions.

Is there a better way?

Thanks,
Iker Arizmendi






More information about the Python-list mailing list