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