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_GetAtt r and PyWrapperDescrO bject
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_Obj ect;
/* Forward declarations */
static PyTypeObject SillyNumber_Typ e;
#define SillyNumber_Che ck(op) PyObject_TypeCh eck(op,
&SillyNumber_Ty pe)
static PyObject *
new_SillyNumber (PyTypeObject *type, double value)
{
PyObject *self;
self = type->tp_alloc(typ e, 0);
if (self == NULL)
return NULL;
((SillyNumber_O bject *)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_ParseTu pleAndKeywords( 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_C heck(left) || !SillyNumber_Ch eck(right)) {
Py_INCREF(Py_No tImplemented);
return Py_NotImplement ed;
}
sum = (((SillyNumber_ Object *)left)->value +
((SillyNumber_O bject *)right)->value);
return new_SillyNumber (&SillyNumber_T ype, sum);
}
static PyObject *
SillyNumber_rad d(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_met hods[] = {
{"__add__", SillyNumber_add , METH_O | METH_COEXIST,
"Add two SillyNumbers."} ,
{"__radd__", SillyNumber_rad d, METH_O | METH_COEXIST,
"Same as __add__."},
{NULL, NULL, 0, NULL}
};
static PyTypeObject SillyNumber_Typ e = {
PyObject_HEAD_I NIT(NULL)
0, /* ob_size */
"silly.SillyNum ber", /* tp_name */
sizeof(SillyNum ber_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_DEFA ULT | /* tp_flags */
Py_TPFLAGS_CHEC KTYPES | /* PyNumberMethods do their own
coercion */
Py_TPFLAGS_BASE TYPE, /* SillyNumber_Typ e allows subclassing
*/
"Silly float numbers", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffs et */
0, /* tp_iter */
0, /* tp_iternext */
SillyNumber_met hods, /* 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_Typ e) < 0)
return;
Py_INCREF(&Sill yNumber_Type);
PyModule_AddObj ect(module, "SillyNumbe r", (PyObject *)
&SillyNumber_Ty pe);
}
/* end of silly module */
Results from the interactive session:
>>import silly
print silly.SillyNumb er.__add__.__do c__
Add two SillyNumbers.
>>print silly.SillyNumb er.__radd__.__d oc__
Same as __add__.
>>n1 = silly.SillyNumb er(3)
n2 = silly.SillyNumb er(3.14)
type(n1 + n2) is silly.SillyNumb er
True
HTH,
Ziga