implementing reduce protocol in C
Alex Martelli
aleax at aleax.it
Fri Sep 20 10:32:41 EDT 2002
Tom Widrick wrote:
...
> static PyObject *
> proto_reduce(self)
> HyProtoObject *self;
I recommend you use "ANSI C" style as a habit:
static PyObject*
proto_reduce(HyProtoObject* self)
it may not matter here, but one day you'll be glad you got into
this habit. And since Python does now require an ANSI/ISO
compatible C compiler, there's no downside.
> {
> PyObject *args;
> PyObject *result;
>
> args = PyTuple_New(5);
> if(args == NULL)
> return NULL;
>
> PyTuple_SET_ITEM(args, 0, self->po_name);
> Py_INCREF(self->po_name);
> PyTuple_SET_ITEM(args, 1, self->po_parents);
> Py_INCREF(self->po_parents);
> PyTuple_SET_ITEM(args, 2, self->po_children);
> Py_INCREF(self->po_children);
> PyTuple_SET_ITEM(args, 3, self->po_doc);
> Py_INCREF(self->po_doc);
> PyTuple_SET_ITEM(args, 4, self->po_dict);
> Py_INCREF(self->po_dict);
>
> result = Py_BuildValue("(OOO)", self->ob_type, Py_None, args);
> Py_DECREF(args);
> return result;
> };
>
> Any better?
Much better, I think. I believe you can save the last
Py_DECREF by using "(OON)" as the first arg to Py_BuildValue,
telling it to steal a reference to the third argument, but
that's not crucial.
Back to your main problem however -- things are NOT rosy.
Check out:
http://mail.python.org/pipermail/python-bugs-list/2002-March/010707.html
If I read this correctly, the case where __reduce__ returns a
second argument of None is being deprecated and is not well
supported anyway. Thus, you probably want to avoid it. I think
this makes the rest of the discussion moot.
Rather, you probably want to expose a factory function to be
passed as the first item in the tuple returned by __reduce__
(you may then want to return a 2-items tuple rather than a
3-items one from __reduce__, perhaps). Just make sure said
first item exposes an attribute named __safe_for_unpickling__
with a true value, or register it as a "safe constructor" with
module copy_reg.
(As an aside -- this is the kind of tasks that I usually handle
with a PyRun_String call in my C-coded-module's init function:
they're SO much easier to express in Python, and they're one-off,
thus performance-insensitive tasks anyway; however, I've been
criticized by important and knowledgeable Pythonistas for this
habit -- didn't really understand the reason for the criticism,
but, anyway, use this hint at your own risk:-).
Alex
More information about the Python-list
mailing list