Python/C API: Python class instance information in C?
Bernt Ribbum
bernt at tordivel.no
Fri Mar 21 04:10:13 EST 2003
Thanks Alex,
The trick was to use the Object Protocol -- there I can find anything I
want.
(And thanks for compiling the Python Cookbook. That one is invaluable
sometimes ;-)
--
- Bernt
---------------------------------------------------------------------------
TORDIVEL AS http://www.tordivel.no
Storgata 20 0184 OSLO NORWAY
Tel +47 2315 8700 Fax +47 2315 8701
Bernt Ribbum bernt at tordivel.no bernt.ribbum at ieee.org
Direct: +47 2315 8714 Mobile: +47 906 106 85
---------------------------------------------------------------------------
"Alex Martelli" <aleax at aleax.it> wrote in message
news:AyAea.92650$pG1.2015177 at news1.tin.it...
> <posted & mailed>
>
> Bernt Ribbum wrote:
>
> > In a C module function, is it possible to extract information about a
> > Python class instance being sent as argument?
>
> Yes. You can basically do in your C code all that you might do from
> Python code, albeit more clumsily and less productively of course. And
> this in particular applies to introspection, as well as other tasks.
>
>
> > To explain a bit further... A C module (METH_VARARGS wrapper) function
> > prototype looks something like
> >
> > PyObject *spam_func(PyObject *self, PyObject *args);
> >
> > The Python arguments are found (possibly inside a tuple) in "args", and
I
> > can handle this for standard Python types like ints, floats, etc., and
> > also for types exported from my C module. What I stumble on, is Python
> > code like this:
> >
> > import spam
> > class X:
> > pass
> > x = X()
> > spam.func(x)
> >
> > In this case I don't know how to extract information about the object.
All
> > I can find (from the C debugger) is that the object in question has an
> > ob_type of _PyInstance_Type. (A call to PyInstance_Check() will return
> > true, but unfortunately the documentation states "There are very few
> > functions specific to instance objects". In fact, there is only the
check
> > function above and two New functions. Nothing else.)
> >
> > Is it possible for me to get more information here? I would like to
know,
> > at least, that this object is of type "class X" or similar.
>
> By PyInstance_Check you identify instances of CLASSIC classes only, of
> course; i.e. if in your example above X inherited from object (and thus
> was a newstyle class) its instances wouldn't pass PyInstance_Check. If
> you also want to handle instances of newstyle classes you'll have to
> work those differently. But let's focus for now on classic class
isntances.
>
> However, the general idea is that you work with the abstract protocol,
> i.e. the PyObject_... functions, getting the relevant attributes. Here
> is one silly example (not thoroughly tested) -- save as intro.py:
>
> #include <Python.h>
> #include <stdio.h>
>
> static PyObject*
> intro(PyObject* self, PyObject* args)
> {
> PyObject *theobj, *theclas, *thecnam;
> if(!PyArg_ParseTuple(args, "O", &theobj))
> return 0;
> if(PyInstance_Check(theobj)) {
> printf("Is an instance.\n");
> theclas = PyObject_GetAttrString(theobj, "__class__");
> if(!theclas)
> return 0;
> thecnam = PyObject_GetAttrString(theclas, "__name__");
> if(!thecnam) {
> Py_DECREF(theclas);
> return 0;
> }
> if(!PyString_Check(thecnam)) {
> Py_DECREF(theclas);
> Py_DECREF(thecnam);
> return PyErr_Format(PyExc_RuntimeError,
> "class name is not a string (?)");
> }
> printf("of class %s\n", PyString_AS_STRING(thecnam));
> Py_DECREF(theclas);
> Py_DECREF(thecnam);
> } else {
> printf("Not an instance.\n");
> }
> return Py_BuildValue("");
> }
>
> static PyMethodDef introMethods[] = {
> {"intro", intro, METH_VARARGS, "introspection example"},
> {0}
> };
>
> void
> initintro(void)
> {
> Py_InitModule("intro", introMethods);
> }
>
> and build/install with the usual setup.py:
>
> from distutils.core import setup, Extension
>
> setup(name = "intro",
> version = "1.0",
> description = "introspection from C",
> maintainer = "Alex Martelli",
> maintainer_email = "aleaxit at yahoo.com",
>
> ext_modules = [ Extension('intro', sources=['intro.c']) ]
> )
>
>
> Now for example:
>
> >>> import intro
> >>> intro.intro(23)
> Not an instance.
> >>> class X: pass
> ...
> >>> intro.intro(X())
> Is an instance.
> of class X
> >>>
>
>
>
> Alex
>
More information about the Python-list
mailing list