[Python-checkins] python/nondist/sandbox/itertools itertools.c,1.2,1.3 libitertools.tex,1.3,1.4 test_itertools.py,1.1,1.2 todo.txt,1.3,1.4

rhettinger@users.sourceforge.net rhettinger@users.sourceforge.net
Sun, 26 Jan 2003 20:24:16 -0800


Update of /cvsroot/python/python/nondist/sandbox/itertools
In directory sc8-pr-cvs1:/tmp/cvs-serv10416

Modified Files:
	itertools.c libitertools.tex test_itertools.py todo.txt 
Log Message:
Added imap()

Index: itertools.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/itertools/itertools.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** itertools.c	27 Jan 2003 00:27:41 -0000	1.2
--- itertools.c	27 Jan 2003 04:24:14 -0000	1.3
***************
*** 2,5 ****
--- 2,161 ----
  #include "Python.h"
  
+ /* imap object ************************************************************/
+ 
+ typedef struct {
+         PyObject_HEAD
+         PyObject *iters;
+ 	PyObject *argtuple;
+ 	PyObject *func;
+ } imapobject;
+ 
+ PyTypeObject imap_type;
+ 
+ static PyObject *
+ imap_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+ {
+         PyObject *it, *iters, *argtuple;
+         imapobject *lz;
+ 	int numargs, i;
+ 
+ 	numargs = PyTuple_Size(args);
+ 	if (numargs == 0) {
+ 		// XXX raise Err for not having a function arg
+ 		return NULL;
+ 	}
+ 
+ 	iters = PyTuple_New(numargs-1);
+ 	if (iters == NULL)
+ 		return NULL;
+ 
+ 	argtuple = PyTuple_New(numargs-1);
+ 	if (argtuple == NULL) {
+ 		Py_DECREF(iters);
+ 		return NULL;
+ 	}
+ 
+ 	for (i=1 ; i<numargs ; i++) {
+ 		/* Get iterator. */
+ 		it = PyObject_GetIter(PyTuple_GET_ITEM(args, i));
+ 		if (it == NULL) {
+ 			Py_DECREF(argtuple);
+ 			Py_DECREF(iters);
+ 			return NULL;
+ 		}
+ 		PyTuple_SET_ITEM(iters, i-1, it);
+ 	}
+ 
+         /* create imapobject structure */
+         lz = (imapobject *)type->tp_alloc(type, 0);
+         if (lz == NULL) {
+ 		Py_DECREF(argtuple);
+                 Py_DECREF(iters);
+                 return NULL;
+         }
+         lz->iters = iters;
+ 	lz->argtuple = argtuple;
+ 	lz->func = PyTuple_GET_ITEM(args, 0);
+ 
+         return (PyObject *)lz;
+ }
+ 
+ static void
+ imap_dealloc(imapobject *lz)
+ {
+         PyObject_GC_UnTrack(lz);
+         //Py_XDECREF(lz->argtuple);
+         //Py_XDECREF(lz->iters);
+         lz->ob_type->tp_free(lz);
+ }
+ 
+ static int
+ imap_traverse(imapobject *lz, visitproc visit, void *arg)
+ {
+         if (lz->argtuple)
+                 return visit(lz->argtuple, arg);
+         return 0;
+ }
+ 
+ static PyObject *
+ imap_next(imapobject *lz)
+ {
+         PyObject *val;
+         PyObject *iters=lz->iters, *argtuple=lz->argtuple;
+ 	int numargs, i;
+ 
+ 	numargs = PyTuple_Size(lz->iters);
+ 
+ 	for (i=0 ; i<numargs ; i++) {
+ 		val = PyIter_Next(PyTuple_GET_ITEM(lz->iters, i));
+ 		if (val == NULL) 
+ 			return NULL;
+ 		PyTuple_SET_ITEM(argtuple, i, val);
+ 	}
+         return PyObject_Call(lz->func, argtuple, NULL);
+ }
+ 
+ static PyObject *
+ imap_getiter(PyObject *lz)
+ {
+         Py_INCREF(lz);
+         return lz;
+ }
+ 
+ PyDoc_STRVAR(imap_doc,
+ "imap(func, *iterables) --> imap object\n\
+ \n\
+ Make an iterator that computes the function using arguments from\n\
+ each of the iterables.  Like map() except 1) that it returns\n\
+ an iterator instead of a list, 2) that it stops when the shortest\n\
+ iterable is exhausted instead of filling in None for shorter\n\
+ iterables, and 3) that it does not accept None for func.");
+ 
+ PyTypeObject imap_type = {
+         PyObject_HEAD_INIT(NULL)
+         0,                              /* ob_size */
+         "itertools.imap",             /* tp_name */
+         sizeof(imapobject),           /* tp_basicsize */
+         0,                              /* tp_itemsize */
+         /* methods */
+         (destructor)imap_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 */
+         imap_doc,                       /* tp_doc */
+         (traverseproc)imap_traverse,    /* tp_traverse */
+         0,                              /* tp_clear */
+         0,                              /* tp_richcompare */
+         0,                              /* tp_weaklistoffset */
+         (getiterfunc)imap_getiter,      /* tp_iter */
+         (iternextfunc)imap_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 */
+         imap_new,                     /* tp_new */
+         PyObject_GC_Del,                /* tp_free */
+ };
+ 
+ 
  /* times object ************************************************************/
  
***************
*** 195,199 ****
  
  PyDoc_STRVAR(ifilter_doc,
! "filter(function or None, sequence [, invert]) --> ifilter object\n\
  \n\
  Return those items of sequence for which function(item) is true.  If\n\
--- 351,355 ----
  
  PyDoc_STRVAR(ifilter_doc,
! "ifilter(function or None, sequence [, invert]) --> ifilter object\n\
  \n\
  Return those items of sequence for which function(item) is true.  If\n\
***************
*** 648,655 ****
          m = Py_InitModule3("itertools", NULL, module_doc);
  
          if (PyType_Ready(&times_type) < 0)
                  return;
          Py_INCREF(&times_type);
-         PyModule_AddObject(m, "times", (PyObject *)&times_type);
  
          if (PyType_Ready(&ifilter_type) < 0)
--- 804,816 ----
          m = Py_InitModule3("itertools", NULL, module_doc);
  
+         PyModule_AddObject(m, "imap", (PyObject *)&imap_type);
+         if (PyType_Ready(&imap_type) < 0)
+                 return;
+         Py_INCREF(&imap_type);
+ 
+         PyModule_AddObject(m, "times", (PyObject *)&times_type);
          if (PyType_Ready(&times_type) < 0)
                  return;
          Py_INCREF(&times_type);
  
          if (PyType_Ready(&ifilter_type) < 0)

Index: libitertools.tex
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/itertools/libitertools.tex,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** libitertools.tex	27 Jan 2003 01:35:20 -0000	1.3
--- libitertools.tex	27 Jan 2003 04:24:14 -0000	1.4
***************
*** 27,31 ****
          \code{imap(\var{f}, count())} and produce an equivalent result.
  
- 
      \item Some tools were dropped because they offer no advantage over their
          pure python counterparts or because their behavior was too
--- 27,30 ----
***************
*** 44,48 ****
          being written in C is its speed advantage.
  
!         For instance, Python's
          \module{__builtins__} module has an easy-to-use, no surprises version
          of \function(zip()).  This module's corresponding function,
--- 43,47 ----
          being written in C is its speed advantage.
  
!         For instance, the
          \module{__builtins__} module has an easy-to-use, no surprises version
          of \function(zip()).  This module's corresponding function,
***************
*** 57,62 ****
          one output list (saving the time to allocate and build a tuple on
  	every pass).  Though very fast, using \function{loopzip()} outside of
!         a \keyword{for} loop can result in surprising behavior and an
!         unwelcome refresher lesson in mutability.
  
      \item Another source of value comes from standardizing a core set of tools
--- 56,61 ----
          one output list (saving the time to allocate and build a tuple on
  	every pass).  Though very fast, using \function{loopzip()} outside of
!         a \keyword{for} loop or other itertool can result in surprising
!         behavior and an unwelcome refresher lesson in mutability.
  
      \item Another source of value comes from standardizing a core set of tools
***************
*** 107,110 ****
--- 106,126 ----
  \end{funcdesc}
  
+ \begin{funcdesc}{imap}{func, *iterables}
+   Make an iterator that computes the function using arguments from
+   each of the iterables.  Like \function{map()} except 1) that it returns
+   an iterator instead of a list, 2) that it stops when the shortest
+   iterable is exhausted instead of filling in \code{None} for shorter
+   iterables, and 3) that it does not accept \code{None} for \var{func}.
+   Equivalent to:
+ 
+   \begin{verbatim}
+      def imap(func, *iterables):
+ 	 iterables = map(iter, iterables)
+          while True:
+ 	     args = [i.next() for i in iterables]
+ 	     yield f(*args)
+   \end{verbatim}
+ \end{funcdesc}
+ 
  \begin{funcdesc}{loopzip}{*iterables}
    Make an iterator that aggregates elements from each of the iterables.
***************
*** 184,192 ****
  
  \begin{verbatim}
! >>> enumerate = lambda s: izip(count(), s)
! >>> tabulate = lambda f: imap(f, count())
! >>> iteritems = lambda d: izip(d.iterkeys(), d.itervalues())
! >>> repeat = lambda o: cycle([o])
! >>> nth = lambda s, n:  islice(n, n+1).next()
  
  \end{verbatim}
--- 200,211 ----
  
  \begin{verbatim}
! >>> def enumerate(s):
! ...     return izip(count(), s)
! >>> def tabulate(f):
! ...     return imap(f, count())
! >>> def iteritems(d):
! ...     return izip(d.iterkeys(), d.itervalues())
! >>> def nth(s, n):
! ...     return islice(n, n+1).next()
  
  \end{verbatim}

Index: test_itertools.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/itertools/test_itertools.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** test_itertools.py	27 Jan 2003 00:16:51 -0000	1.1
--- test_itertools.py	27 Jan 2003 04:24:14 -0000	1.2
***************
*** 20,29 ****
  
      def test_repeat(self):
!         self.assertEqual(zip(xrange(3),repeat('a')), [(0, 'a'), (1, 'a'), (2, 'a')])
  
      def test_times(self):
          self.assertEqual(list(times(3)), [None]*3)
  
! 
  def test_main():
      suite = unittest.TestSuite()
--- 20,34 ----
  
      def test_repeat(self):
!         self.assertEqual(zip(xrange(3),repeat('a')),
!                          [(0, 'a'), (1, 'a'), (2, 'a')])
  
      def test_times(self):
          self.assertEqual(list(times(3)), [None]*3)
  
!     def test_imap(self):
!         import operator
!         self.assertEqual(list(imap(operator.pow, range(3), range(1,7))),
!                          [0**1, 1**2, 2**3])
!  
  def test_main():
      suite = unittest.TestSuite()

Index: todo.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/itertools/todo.txt,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** todo.txt	27 Jan 2003 01:35:21 -0000	1.3
--- todo.txt	27 Jan 2003 04:24:14 -0000	1.4
***************
*** 1,5 ****
  Add:
     islice(iterator, start, stop, step)
-    imap(func, iter1, iter2, ...)
     iapply
     starmap()
--- 1,4 ----