[Python-checkins] python/nondist/sandbox/itertools itertools.c,1.4,1.5 libitertools.tex,1.5,1.6 test_itertools.py,1.3,1.4 todo.txt,1.5,1.6
rhettinger@users.sourceforge.net
rhettinger@users.sourceforge.net
Mon, 27 Jan 2003 02:03:13 -0800
- Previous message: [Python-checkins] python/nondist/sandbox/itertools itertools.c,1.3,1.4 libitertools.tex,1.4,1.5 test_itertools.py,1.2,1.3 todo.txt,1.4,1.5
- Next message: [Python-checkins] python/nondist/sandbox/itertools itertools.c,1.5,1.6 libitertools.tex,1.6,1.7 todo.txt,1.6,1.7
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvsroot/python/python/nondist/sandbox/itertools
In directory sc8-pr-cvs1:/tmp/cvs-serv3903
Modified Files:
itertools.c libitertools.tex test_itertools.py todo.txt
Log Message:
Added islice() and stronger error checking.
Index: itertools.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/itertools/itertools.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** itertools.c 27 Jan 2003 05:24:40 -0000 1.4
--- itertools.c 27 Jan 2003 10:02:59 -0000 1.5
***************
*** 2,5 ****
--- 2,170 ----
#include "Python.h"
+ /* islice object ************************************************************/
+
+ typedef struct {
+ PyObject_HEAD
+ PyObject *it;
+ long next;
+ long stop;
+ long step;
+ long cnt;
+ } isliceobject;
+
+ PyTypeObject islice_type;
+
+ static PyObject *
+ islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+ {
+ PyObject *seq;
+ long a1=0, a2=0, a3=0, start=0, stop=0, step=1;
+ PyObject *it;
+ int numargs;
+ isliceobject *lz;
+
+ numargs = PyTuple_Size(args);
+ if (!PyArg_ParseTuple(args, "Ol|ll:islice", &seq, &a1, &a2, &a3))
+ return NULL;
+
+ if (numargs == 2) {
+ stop = a1;
+ } else if (numargs == 3) {
+ start = a1;
+ stop = a2;
+ } else {
+ start = a1;
+ stop = a2;
+ step = a3;
+ }
+
+ if (start<0 || stop<0) {
+ PyErr_SetString(PyExc_ValueError,
+ "Indices for islice() must be positive.");
+ return NULL;
+ }
+
+ if (step<1) {
+ PyErr_SetString(PyExc_ValueError,
+ "Step must be one or larger for islice().");
+ return NULL;
+ }
+
+ /* Get iterator. */
+ it = PyObject_GetIter(seq);
+ if (it == NULL)
+ return NULL;
+
+ /* create isliceobject structure */
+ lz = (isliceobject *)type->tp_alloc(type, 0);
+ if (lz == NULL) {
+ Py_DECREF(it);
+ return NULL;
+ }
+ lz->it = it;
+ lz->next = start;
+ lz->stop = stop;
+ lz->step = step;
+ lz->cnt = 0L;
+
+ return (PyObject *)lz;
+ }
+
+ static void
+ islice_dealloc(isliceobject *lz)
+ {
+ PyObject_GC_UnTrack(lz);
+ Py_XDECREF(lz->it);
+ lz->ob_type->tp_free(lz);
+ }
+
+ static int
+ islice_traverse(isliceobject *lz, visitproc visit, void *arg)
+ {
+ if (lz->it)
+ return visit(lz->it, arg);
+ return 0;
+ }
+
+ static PyObject *
+ islice_next(isliceobject *lz)
+ {
+ PyObject *item;
+
+ while (lz->cnt < lz->next) {
+ item = PyIter_Next(lz->it);
+ if (item == NULL)
+ return NULL;
+ Py_DECREF(item);
+ lz->cnt++;
+ }
+ if (lz->stop != 0 && lz->cnt >= lz->stop)
+ return NULL;
+ item = PyIter_Next(lz->it);
+ if (item == NULL)
+ return NULL;
+ lz->cnt += 1;
+ lz->next += lz->step;
+ return item;
+ }
+
+ static PyObject *
+ islice_getiter(PyObject *lz)
+ {
+ Py_INCREF(lz);
+ return lz;
+ }
+
+ PyDoc_STRVAR(islice_doc,
+ "islice(function, sequence) --> islice object\n\
+ \n\
+ Return an iterator whose values are returned from the function evaluated\n\
+ with a argument tuple taken from the given sequence.");
+
+ PyTypeObject islice_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "itertools.islice", /* tp_name */
+ sizeof(isliceobject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)islice_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_BASETYPE, /* tp_flags */
+ islice_doc, /* tp_doc */
+ (traverseproc)islice_traverse, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)islice_getiter, /* tp_iter */
+ (iternextfunc)islice_next, /* tp_iternext */
+ 0, /* 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 */
+ PyType_GenericAlloc, /* tp_alloc */
+ islice_new, /* tp_new */
+ PyObject_GC_Del, /* tp_free */
+ };
+
/* starmap object ************************************************************/
***************
*** 150,155 ****
numargs = PyTuple_Size(args);
! if (numargs == 0) {
! // XXX raise Err for not having a function arg
return NULL;
}
--- 315,321 ----
numargs = PyTuple_Size(args);
! if (numargs < 2) {
! PyErr_SetString(PyExc_TypeError,
! "imap() must have at least two arguments.");
return NULL;
}
***************
*** 305,308 ****
--- 471,480 ----
return NULL;
+ if (cnt < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "count for imap() cannot be negative.");
+ return NULL;
+ }
+
/* create timesobject structure */
lz = (timesobject *)PyObject_New(timesobject, ×_type);
***************
*** 933,936 ****
--- 1105,1113 ----
PyObject *m;
m = Py_InitModule3("itertools", NULL, module_doc);
+
+ PyModule_AddObject(m, "islice", (PyObject *)&islice_type);
+ if (PyType_Ready(&islice_type) < 0)
+ return;
+ Py_INCREF(&islice_type);
PyModule_AddObject(m, "starmap", (PyObject *)&starmap_type);
Index: libitertools.tex
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/itertools/libitertools.tex,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** libitertools.tex 27 Jan 2003 05:24:40 -0000 1.5
--- libitertools.tex 27 Jan 2003 10:03:04 -0000 1.6
***************
*** 123,126 ****
--- 123,148 ----
\end{funcdesc}
+ \begin{funcdesc}{islice}{iterable, \optional{start,} stop \optional{, step}}
+ Make an iterator that returns selected elements from the iterable.
+ If \var{start} is non-zero, then elements from the iterable are skiped
+ until start is reached. Afterward, elements are returned consecutively
+ unless \var{step} is set higher than one which results in items being
+ skipped. If \var{stop} is specified, then iteration stops at the
+ specified element position; otherwise, it continues indefinitely or
+ until the iterable is exhausted. Unlike regular slicing,
+ \function{islice()} does not support negative values for \var{start},
+ \var{stop}, or \var{step}. Equivalent to:
+
+ \begin{verbatim}
+ def islice(func, iterable, *args):
+ i = 0
+ for j in xrange(*args):
+ while i != j:
+ _ = iterable.next()
+ i += 1
+ yield iterable.next()
+ \end{verbatim}
+ \end{funcdesc}
+
\begin{funcdesc}{loopzip}{*iterables}
Make an iterator that aggregates elements from each of the iterables.
***************
*** 170,175 ****
\begin{funcdesc}{times}{n}
Make an iterator that returns None \var{n} times.
! Used for looping a specific number of times without creating a number object
! on each pass. Equivalent to:
\begin{verbatim}
--- 192,197 ----
\begin{funcdesc}{times}{n}
Make an iterator that returns None \var{n} times.
! Used for looping a specific number of times without creating a number
! object on each pass. Equivalent to:
\begin{verbatim}
Index: test_itertools.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/itertools/test_itertools.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** test_itertools.py 27 Jan 2003 05:24:40 -0000 1.3
--- test_itertools.py 27 Jan 2003 10:03:06 -0000 1.4
***************
*** 7,10 ****
--- 7,11 ----
self.assertEqual(zip('abc',count()), [('a', 0), ('b', 1), ('c', 2)])
self.assertEqual(zip('abc',count(3)), [('a', 3), ('b', 4), ('c', 5)])
+ self.assertRaises(TypeError, count, 2, 3)
def test_ifilter(self):
***************
*** 13,16 ****
--- 14,21 ----
self.assertEqual(list(ifilter(isEven, range(6))), [0,2,4])
self.assertEqual(list(ifilter(isEven, range(6), True)), [1,3,5])
+ self.assertRaises(TypeError, ifilter)
+ self.assertRaises(TypeError, ifilter, 3)
+ self.assertRaises(TypeError, ifilter, isEven, 3)
+ self.assertRaises(TypeError, ifilter, isEven, [3], True, 4)
def test_loopzip(self):
***************
*** 18,28 ****
--- 23,36 ----
self.assertEqual(ans, [('a', 0), ('b', 1), ('c', 2)])
self.assertEqual(list(loopzip('abc',count())), [['c', 2]] * 3)
+ self.assertRaises(TypeError, loopzip)
def test_repeat(self):
self.assertEqual(zip(xrange(3),repeat('a')),
[(0, 'a'), (1, 'a'), (2, 'a')])
+ self.assertRaises(TypeError, repeat)
def test_times(self):
self.assertEqual(list(times(3)), [None]*3)
+ self.assertRaises(ValueError, times, -1)
def test_imap(self):
***************
*** 30,33 ****
--- 38,43 ----
self.assertEqual(list(imap(operator.pow, range(3), range(1,7))),
[0**1, 1**2, 2**3])
+ self.assertRaises(TypeError, imap)
+ self.assertRaises(TypeError, imap, operator.neg)
def test_starmap(self):
***************
*** 36,39 ****
--- 46,73 ----
[0**1, 1**2, 2**3])
+ def test_islice(self):
+ for args in [ # islice(args) should agree with range(args)
+ (10, 20, 3),
+ (10, 3, 20),
+ (10, 20),
+ (10, 3),
+ (20,)
+ ]:
+ self.assertEqual(list(islice(xrange(100), *args)), range(*args))
+
+ for args, tgtargs in [ # Stop when seqn is exhausted
+ ((10, 110, 3), ((10, 100, 3))),
+ ((10, 110), ((10, 100))),
+ ((110,), (100,))
+ ]:
+ self.assertEqual(list(islice(xrange(100), *args)), range(*tgtargs))
+
+
+ self.assertRaises(TypeError, islice, xrange(10))
+ self.assertRaises(TypeError, islice, xrange(10), 1, 2, 3, 4)
+ self.assertRaises(ValueError, islice, xrange(10), -5, 10, 1)
+ self.assertRaises(ValueError, islice, xrange(10), 1, -5, -1)
+ self.assertRaises(ValueError, islice, xrange(10), 1, 10, -1)
+ self.assertRaises(ValueError, islice, xrange(10), 1, 10, 0)
def test_main():
Index: todo.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/itertools/todo.txt,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** todo.txt 27 Jan 2003 05:24:40 -0000 1.5
--- todo.txt 27 Jan 2003 10:03:07 -0000 1.6
***************
*** 1,5 ****
Add:
! islice(iterator, start, stop, step)
! iapply
takewhile(pred, seqn)
dropwhile(pred, seqn)
--- 1,4 ----
Add:
! iapply(func) ?? what did this do in SML
takewhile(pred, seqn)
dropwhile(pred, seqn)
***************
*** 9,14 ****
refcounts
-
Things dropped because they bug me:
cycle(seqn) requires auxilliary storage (which is surprising
behavior for iterators). This is best left for pure python.
--- 8,16 ----
refcounts
Things dropped because they bug me:
cycle(seqn) requires auxilliary storage (which is surprising
behavior for iterators). This is best left for pure python.
+
+ Things that just bug me:
+ islice is supposed to looklike i-slice but can be read as is-lice
+
- Previous message: [Python-checkins] python/nondist/sandbox/itertools itertools.c,1.3,1.4 libitertools.tex,1.4,1.5 test_itertools.py,1.2,1.3 todo.txt,1.4,1.5
- Next message: [Python-checkins] python/nondist/sandbox/itertools itertools.c,1.5,1.6 libitertools.tex,1.6,1.7 todo.txt,1.6,1.7
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]