Nick Alexander wrote: > Hello, > > I am writing a python extension (compiled C code) that defines an > extension type with PyNumberMethods. Everything works swimmingly, > except I can't deduce a clean way to set the docstring for tp_* > methods. That is, I always have > > type.__long__.__doc__ == 'x.__long__() <==> long(x)' > > which a quick glance at the Python 2.5 source shows is the default. > > I have found that I can use PyObject_GetAttr and PyWrapperDescrObject > and set the descriptor objects d_base->doc to a char pointer... but I > can't tell if this is safe. Or the right way to do it. > > If I'm on the wrong list, please let me know! > Thanks, > Nick Alexander
I think that the right way is to add the methods to the tp_methods slot and use METH_COEXIST in the PyMethodDef flags field. Example: /* start of silly module */ #include "Python.h" typedef struct { PyObject_HEAD double value; } SillyNumber_Object; /* Forward declarations */ static PyTypeObject SillyNumber_Type; #define SillyNumber_Check(op) PyObject_TypeCheck(op, &SillyNumber_Type) static PyObject * new_SillyNumber(PyTypeObject *type, double value) { PyObject *self; self = type->tp_alloc(type, 0); if (self == NULL) return NULL; ((SillyNumber_Object *)self)->value = value; return self; } static PyObject * SillyNumber_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { double value = 0.0; static char *kwlist[] = {"value", 0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|d:SillyNumber", kwlist, &value)) return NULL; return new_SillyNumber(type, value); } static PyObject * SillyNumber_add(PyObject *left, PyObject *right) { double sum; if (!SillyNumber_Check(left) || !SillyNumber_Check(right)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } sum = (((SillyNumber_Object *)left)->value + ((SillyNumber_Object *)right)->value); return new_SillyNumber(&SillyNumber_Type, sum); } static PyObject * SillyNumber_radd(PyObject *right, PyObject *left) { return SillyNumber_add(left, right); } static PyNumberMethods SillyNumber_as_number = { SillyNumber_add, /* nb_add */ 0, /* nb_subtract */ 0, /* nb_multiply */ 0, /* nb_divide */ 0, /* nb_remainder */ 0, /* nb_divmod */ 0, /* nb_power */ 0, /* nb_negative */ 0, /* nb_positive */ 0, /* nb_absolute */ 0, /* nb_nonzero */ }; static PyMethodDef SillyNumber_methods[] = { {"__add__", SillyNumber_add, METH_O | METH_COEXIST, "Add two SillyNumbers."}, {"__radd__", SillyNumber_radd, METH_O | METH_COEXIST, "Same as __add__."}, {NULL, NULL, 0, NULL} }; static PyTypeObject SillyNumber_Type = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "silly.SillyNumber", /* tp_name */ sizeof(SillyNumber_Object), /* tp_basicsize */ 0, /* tp_itemsize */ 0, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ &SillyNumber_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | /* tp_flags */ Py_TPFLAGS_CHECKTYPES | /* PyNumberMethods do their own coercion */ Py_TPFLAGS_BASETYPE, /* SillyNumber_Type allows subclassing */ "Silly float numbers", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ SillyNumber_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ SillyNumber_new, /* tp_new */ 0, /* tp_free */ }; static PyMethodDef silly_methods[] = { {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initsilly(void) { PyObject *module; module = Py_InitModule3("silly", silly_methods, "silly floating number type"); if (module == NULL) return; if (PyType_Ready(&SillyNumber_Type) < 0) return; Py_INCREF(&SillyNumber_Type); PyModule_AddObject(module, "SillyNumber", (PyObject *) &SillyNumber_Type); } /* end of silly module */ Results from the interactive session: >>> import silly >>> print silly.SillyNumber.__add__.__doc__ Add two SillyNumbers. >>> print silly.SillyNumber.__radd__.__doc__ Same as __add__. >>> n1 = silly.SillyNumber(3) >>> n2 = silly.SillyNumber(3.14) >>> type(n1 + n2) is silly.SillyNumber True HTH, Ziga -- http://mail.python.org/mailman/listinfo/python-list