Subclassing in C

Iker Arizmendi iker at research.att.com
Tue Sep 14 16:11:03 EDT 2004


After placing a printf statement in both of these methods

     fsmpy_getattro
     PyGrm_GetAttro

I notice that when calling the "type" method of my
subclass like so:

     g = grm.GrmReplace(...)
     print g.type()

only the PyGrm_GetAttro method is called. I expected
that the call to Py_FindMethod would eventually call
fsmpy_getattro since my subclass doesn't have a method
called "type" (here the "type" method has nothing to do
with Python types, it's just what we happen to call
one of our methods).


Regards,
Iker


Iker Arizmendi wrote:
> 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