[Patches] New builtin function repeat?

Neil Schemenauer nascheme@enme.ucalgary.ca
Wed, 5 Apr 2000 19:44:35 -0600


--G4iJoqBmSsgzjUCe
Content-Type: text/plain; charset=us-ascii

I made this module some time about but I still think it is neat.
It creates a new function called repeat (I'm not stuck on the
name).  You can use it like this:

    for line in repeat(sys.stdin.readline):
        ...

The repeat function creates a new sequence object.  The function
supplied is called for __getitem__.  By default, a false value
returned from the function will raise an IndexError.  You can
specifiy an alternate termination value.  For example:

    for line in repeat(sys.stdin.readline, ''):
        ...

would work as well.

While I'm throwing out crazy ideas, how about adding some
sequence methods to PyFileObject?  You could then do:

    file = open(...)
    for line in file:
        ...

Too weird?  Here is a patch and the module.

    Neil

-- 
"The lyf so short, the craft so long to lerne." -- Chaucer

--G4iJoqBmSsgzjUCe
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="file-seq.diff"

diff -cr Python-cvs/Objects/fileobject.c Python-file/Objects/fileobject.c
*** Python-cvs/Objects/fileobject.c	Fri Mar 24 22:32:30 2000
--- Python-file/Objects/fileobject.c	Wed Apr  5 19:37:13 2000
***************
*** 1040,1045 ****
--- 1040,1099 ----
  	return PyMember_Set((char *)f, file_memberlist, name, v);
  }
  
+ /* as_sequence */
+ 
+ static PyObject *
+ file_getitem(self, index)
+ 	PyObject *self;
+ 	int index;
+ {
+ 	PyObject *line;
+ 	if ((line = PyFile_GetLine(self, 0)) == NULL) {
+ 		return NULL;
+ 	}
+ 	if (!PyObject_IsTrue(line)) {
+ 		Py_DECREF(line);
+ 		PyErr_SetString(PyExc_IndexError, "file index out of range");
+ 		return NULL;
+ 	}
+ 	return line;
+ }
+ 
+ static int
+ file_length(self)
+ 	PyObject *self;
+ {
+ 	return 0;
+ }
+ 
+ static PyObject *
+ file_concat(self, other)
+ 	PyObject *self;
+ 	PyObject *other;
+ {
+ 	PyErr_SetString(PyExc_AttributeError, "__concat__");
+ 	return NULL;
+ }
+ 
+ static PyObject *
+ file_repeat(self, count)
+ 	PyObject *self;
+ 	int count;
+ {
+ 	PyErr_SetString(PyExc_AttributeError, "__repeat__");
+ 	return NULL;
+ }
+ 
+ static PySequenceMethods file_as_sequence = {
+ 	(inquiry)file_length, /*sq_length*/
+ 	(binaryfunc)file_concat, /*sq_concat*/
+ 	(intargfunc)file_repeat, /*sq_repeat*/
+ 	(intargfunc)file_getitem, /*sq_item*/
+ 	(intintargfunc)0, /*sq_slice*/
+ 	(intobjargproc)0, /*sq_ass_item*/
+ 	(intintobjargproc)0, /*sq_ass_slice*/
+ };
+ 
  PyTypeObject PyFile_Type = {
  	PyObject_HEAD_INIT(&PyType_Type)
  	0,
***************
*** 1052,1057 ****
--- 1106,1113 ----
  	(setattrfunc)file_setattr, /*tp_setattr*/
  	0,		/*tp_compare*/
  	(reprfunc)file_repr, /*tp_repr*/
+ 	0,		/*tp_as_number*/
+ 	&file_as_sequence,	/*tp_as_sequence*/
  };
  
  /* Interface for the 'soft space' between print items. */

--G4iJoqBmSsgzjUCe
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="repeatmodule.c"

/*
 * A little Python extension module so you can do stuff like:
 * 	
 * 	import sys
 * 	from repeat import repeat
 * 	for line in repeat(sys.stdin.readline):
 * 		...
 *
 * repeat(<function>, [<until>]) -> RepeatObject
 *
 * RepeatObjects are sequences that only support the method __getitem__.
 * <function> is called on __getitem__.  If <until> is not specified a
 * false value from <function> raises an IndexError.  If <until> is
 * specified, if the value is equal to <until> then IndexError is
 * raised.
 * 
 *
 * Neil Schemenauer <nascheme@ucalgary.ca> April, 2000
 * 
 */

#include "Python.h"

typedef struct {
	PyObject_HEAD
	PyObject	*function;
	PyObject	*until;
} repeatObject;

staticforward PyTypeObject repeat_Type;

static repeatObject *
newrepeatObject(args)
	PyObject *args;
{
	repeatObject *self;
	PyObject *function;
	PyObject *until;

	until = NULL;
	if (!PyArg_ParseTuple(args, "O|O", &function, &until))
		return NULL;
	if (!PyCallable_Check(function)) {
		PyErr_SetString(PyExc_TypeError, "callable object required");
		return NULL;
	}
	self = PyObject_NEW(repeatObject, &repeat_Type);
	if (self == NULL)
		return NULL;
	Py_INCREF(function);
	self->function = function;
	if (until != NULL)
		Py_INCREF(until);
	self->until = until;
	return self;
}

static void
repeat_dealloc(self)
	repeatObject *self;
{
	Py_XDECREF(self->function);
	Py_XDECREF(self->until);
	PyMem_DEL(self);
}

static PyObject *
repeat_getitem(self, index)
	repeatObject *self;
	int index;
{
	PyObject *item;

	item = PyEval_CallObject(self->function, NULL);
	if ( item == NULL ) {
		return NULL;
	}
	if ( (self->until && PyObject_Compare(item, self->until) == 0) ||
			(!self->until && !PyObject_IsTrue(item)) ) {
		PyErr_SetString(PyExc_IndexError, "repeat completed");
		return NULL;
	}
	return item;
}

static int
repeat_length(self)
    PyObject *self;
{
    return 0;
}

static PyObject *
repeat_concat(self, other)
    PyObject *self;
    PyObject *other;
{
    PyErr_SetString(PyExc_AttributeError, "__concat__");
    return NULL;
}

static PyObject *
repeat_repeat(self, count)
    PyObject *self;
    int count;
{
    PyErr_SetString(PyExc_AttributeError, "__repeat__");
    return NULL;
}

static PyMethodDef repeat_methods[] = {
	{NULL,		NULL}		/* sentinel */
};

static PySequenceMethods repeat_as_sequence = {
	(inquiry)repeat_length, /*sq_length*/
	(binaryfunc)repeat_concat, /*sq_concat*/
	(intargfunc)repeat_repeat, /*sq_repeat*/
	(intargfunc)repeat_getitem, /*sq_item*/
	(intintargfunc)0, /*sq_slice*/
	(intobjargproc)0, /*sq_ass_item*/
	(intintobjargproc)0, /*sq_ass_slice*/
};

staticforward PyTypeObject repeat_Type = {
	PyObject_HEAD_INIT(NULL)
	0,			/*ob_size*/
	"repeat",		/*tp_name*/
	sizeof(repeatObject),	/*tp_basicsize*/
	0,			/*tp_itemsize*/
	/* methods */
	(destructor)repeat_dealloc, /*tp_dealloc*/
	0,			/*tp_print*/
	(getattrfunc)0, 	/*tp_getattr*/
	0,			/*tp_setattr*/
	0,			/*tp_compare*/
	0,			/*tp_repr*/
	0,			/*tp_as_number*/
	&repeat_as_sequence,	/*tp_as_sequence*/
	0,			/*tp_as_mapping*/
	0,			/*tp_hash*/
};

static PyObject *
repeat_new(self, args)
	PyObject *self; /* Not used */
	PyObject *args;
{
	repeatObject *rv;
	
	rv = newrepeatObject(args);
	if ( rv == NULL )
	    return NULL;
	return (PyObject *)rv;
}

/* List of functions defined in the module */
static PyMethodDef repeatmodule_methods[] = {
	{"repeat",		repeat_new,		1},
	{NULL,		NULL}		/* sentinel */
};


/* Initialization function for the module (*must* be called initrepeat) */
void
initrepeat()
{
	PyObject *m, *d;

	/* Create the module and add the functions */
	repeat_Type.ob_type = &PyType_Type;
	m = Py_InitModule("repeat", repeatmodule_methods);

	/* Add some symbolic constants to the module */
	d = PyModule_GetDict(m);
}

--G4iJoqBmSsgzjUCe--