I wrote my first Python extension library over the last couple of weeks. I took note of all the recommendations to keep track of reference counts, to ensure that objects were not disposed when they shouldn’t be, and were when they should. However, the example code seems to use gotos. And the trouble with these is that they don’t nest and un-nest easily; try to do too much refactoring with them, and you run into the age-old “spaghetti code” problem.
Which is where the do-once block comes in. The basic control flow is this: * Unconditionally initialize all dynamic storage to nil * Do the main body of the code, aborting in any error * Regardless of success or failure of the above, dispose of all allocated dynamic storage, using disposal calls which turn into noops if passed pointers that are already nil. For example, here’s a utility routine from my extension that, passed a Python array object, returns the address and length of the storage: static void GetBufferInfo ( PyObject * FromArray, unsigned long * addr, unsigned long * len ) /* returns the address and length of the data in a Python array object. */ { PyObject * TheBufferInfo = 0; PyObject * AddrObj = 0; PyObject * LenObj = 0; do /*once*/ { TheBufferInfo = PyObject_CallMethod(FromArray, "buffer_info", ""); if (TheBufferInfo == 0) break; AddrObj = PyTuple_GetItem(TheBufferInfo, 0); LenObj = PyTuple_GetItem(TheBufferInfo, 1); if (PyErr_Occurred()) break; Py_INCREF(AddrObj); Py_INCREF(LenObj); *addr = PyInt_AsUnsignedLongMask(AddrObj); *len = PyInt_AsUnsignedLongMask(LenObj); if (PyErr_Occurred()) break; } while (false); Py_XDECREF(AddrObj); Py_XDECREF(LenObj); Py_XDECREF(TheBufferInfo); } /*GetBufferInfo*/ You can pretty much determine by inspection that all the reference counts are properly maintained, no need to trace through convoluted flows of control. -- http://mail.python.org/mailman/listinfo/python-list