Subclassing in C

Iker Arizmendi iker at research.att.com
Tue Sep 14 21:00:31 CEST 2004


Michael Hudson wrote:
> Iker Arizmendi <iker at research.att.com> writes:
> 
>>(*) The class I'm deriving from is defined in another
>>extension module and it has its own tp_getattr method.
> 
> 
> Hmm.  I take it *it's* tp_getattr[o] method isn't
> PyObject_GenericGetAttr then?
> 
> Then your initial post makes more sense; I'm afraid I don't see
> any obvious reason for PyObject_GenericGetAttr to crash.

Ah! I missed the trailing 'o' and set tp_getattr, not
tp_getattro as you suggested. However, after setting it
correctly (I think), things still don't behave as I would
expect (eg, the subclass has the union of its methods and
the base class methods). The complete code is pretty long
so I'm not sure I can post it (most of it deals with non
Python stuff) - but here's a more complete piece that
relates to setting up the classes.

The base class (defined in a separated module) looks
like so:

     static PyMethodDef fsmpymethods[] =
     {
        {
          "type", (PyCFunction) fsmpytype,
           METH_NOARGS,
           "type() -> string\n\nReturn FSM type."
        },
        ...
        {
            NULL, NULL, 0, NULL
        }
     };

     static PyObject*
     fsmpy_getattro(PyObject *obj, PyObject* name)
     {
         return Py_FindMethod(fsmpymethods, obj,
                              PyString_AsString(name));
     }

     PyTypeObject FSMPyType =
     {
        PyObject_HEAD_INIT(NULL)
        0,
        "fsm.Fsm",
        sizeof(FSMPyObject),
        0,
        fsmpy_dealloc,                             /*tp_dealloc*/
        0,                                         /*tp_print*/
        0,                                         /*tp_getattr*/
        0,                                         /*tp_setattr*/
        fsmpy_getattro,                            /*tp_getattro*/
        ...
        0,                                         /*tp_setattro*/
        0,                                         /*tp_as_buffer*/
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
     ...
     };

The base class doesn't have a new or init method as the author
provides an explicit "create" method.

The subclass that I've put together now looks like so (note
that I now use the tp_getattro method, and cleared both
tp_methods and tp_members):

    static PyMethodDef PyGrmReplace_methods[] =
    {
        {
           "mutate", (PyCFunction)PyGrmReplace_mutate,
           METH_VARARGS|METH_KEYWORDS,
           "mutate(fsm1 [, mode]) -> fsm\n"
        },
        ...
        {NULL}
    };

    static PyObject*
    PyGrm_GetAttro(PyObject *obj, PyObject* name)
    {
       return Py_FindMethod(PyGrmReplace_methods, obj,
                            PyString_AsString(name));
    }

    static PyTypeObject PyGrmReplaceType =
    {
       PyObject_HEAD_INIT(NULL)
       0,                               /* ob_size */
       "grm.GrmReplace",                /* tp_name */
        sizeof(PyFsmObject),            /* tp_basicsize */
        0,                              /* tp_itemsize */
        PyGrmReplace_dealloc,           /* tp_dealloc */
        0,                              /* tp_print */
        0,                              /* tp_getattr */
        0,                              /* tp_setattr */
        ...
        PyGrm_GetAttro,                 /* tp_getattro */
        0,                              /* tp_setattro */
        0,                              /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT,             /* tp_flags */
        "GrmReplace objects",           /* tp_doc */
        ...
        0,                              /* tp_methods */
        0,                              /* tp_members */
        ...
        PyGrmReplace_init,              /* tp_init */
        0,                              /* tp_alloc */
        PyGrmReplace_new,               /* tp_new */
    };

    PyMODINIT_FUNC
    initgrm(void)
    {
       PyGrmReplaceType.tp_new = PyGrmReplace_new;
       PyGrmReplaceType.tp_base = pointerToFSMPyType;
       if (PyType_Ready(&PyGrmReplaceType) < 0)
           return;

       PyObject* m = Py_InitModule3("grm", grm_methods,
                    "Python binding for the AT&T GRM library");
       Py_INCREF(&PyGrmReplaceType);
       PyModule_AddObject(m, "GrmReplace", (PyObject*)&PyGrmReplaceType);
    }

And the result of this is that an instance of grm.GrmReplace
makes the mutate method available, but doesn't have the
type() method from the fsm.Fsm class. Is there some "canonical"
form for implementing this?

Thanks again,
Iker


> 
> 
>>Here's the stack trace (via Valgrind), just in case:
> 
> 
> A stack trace from gdb (i.e. with line numbers) would have been more
> use.
> 
> I think you have two options here: (a) make friends with gdb or (b)
> post [a link to, maybe] complete code.
> 
> Cheers,
> mwh
> 



More information about the Python-list mailing list