Recursive loading trouble for immutables

Mel mwilson at the-wire.com
Sun Nov 25 12:07:56 EST 2007


Mel wrote:
> rekkufa wrote:
[ ... ]
>> How to load
>> data that specifies immutables that recursively reference
>> themselves.
> I can imagine a C function that might do it.
[ ... ]

Here's something that works, in the sense of creating a tuple 
containing a self-reference.  I don't know how dangerous it realliy is 
-- haven't tested for memory leaks or any other large-scale trouble.
Also, I've only tested on Python 2.5.1 under Ubuntu Linux.

Called as

idiotuple.idiotuple (a_sequence, a_marker)

it returns a tuple containing the items of a_sequence, except that 
instances of a_marker are replaced by references to the returned 
tuple.   Eg.:

import idiotuple
class IdioMarker: "An object that I will never insert into a tuple."
def showid (x):
     print id(x)
     for y in x:
         print '  ', id(y)

showid (idiotuple.idiotuple ((1,2,3), IdioMarker))
showid (idiotuple.idiotuple ((1, IdioMarker, 3), IdioMarker))



The C code is:


/* $Id$ */
#include <Python.h>

/*=======================================================*/

static PyObject *idiotuple_idiotuple (PyObject *self, PyObject *args)
// In Python, call with
//    sequence contents
//    object marker
// returns
//    tuple containing contents, with instances of marker
//      replaced by borrowed self-references
{
     PyObject *t = NULL;
     PyObject *contents, *marker, *x;
     Py_ssize_t i, n, z;
     if (!PyArg_ParseTuple (args, "OO", &contents, &marker))
         return NULL;
     n = PySequence_Size (contents);
     if (n < 0)
         return NULL;
     t = PyTuple_New (n);    // new tuple
     if (t == NULL)
         return NULL;
     for (i=0; i < n; ++i) {
         x = PySequence_GetItem (contents, i);    // new reference
         if (x != marker) {
             z = PyTuple_SetItem (t, i, x);    // steals the new 
reference to x
             if (z == -1) {
                 goto fail;
             }
         }
         if (x == marker) {
             z = PyTuple_SetItem (t, i, t);    // stolen reference to t
             // Dereference the marker.
             // The internal reference to the tuple is effectively 
'borrowed'.
             // Only external references to the tuple are reflected in 
its reference count.
             Py_DECREF (x);    // dereference the marker
             if (z == -1) {
                 goto fail;
             }
         }
     }
     return t;
fail:
     Py_DECREF (t);    // arrange for the tuple to go away
     return NULL;
} /* idiotuple_idiotuple */


/*=======================================================*/

static PyMethodDef IdioTupleMethods[] = {
     {"idiotuple", idiotuple_idiotuple, METH_VARARGS, "Create a 
possibly self-referential tuple."},
     {NULL, NULL, (int)NULL, NULL}
};

PyMODINIT_FUNC initidiotuple (void)
{
     PyObject *module;
     module = Py_InitModule ("idiotuple", IdioTupleMethods);
}





Setup.py is


# for use by distutils
from distutils.core import setup, Extension

module1 = Extension('idiotuple',
                     sources = ['idiotuple.c'])

setup (name = 'idiotuple',
        version = '1.0',
        description = 'Create a possibly self-referential tuple.',
        author = 'Mel Wilson',
        author_email = 'mwilson at the-wire.com',
        ext_modules = [module1])





More information about the Python-list mailing list