]> granicus.if.org Git - python/commitdiff
C Code:
authorRaymond Hettinger <python@rcn.com>
Sun, 9 Feb 2003 06:40:58 +0000 (06:40 +0000)
committerRaymond Hettinger <python@rcn.com>
Sun, 9 Feb 2003 06:40:58 +0000 (06:40 +0000)
* Removed the ifilter flag wart by splitting it into two simpler functions.
* Fixed comment tabbing in C code.
* Factored module start-up code into a loop.

Documentation:
* Re-wrote introduction.
* Addede examples for quantifiers.
* Simplified python equivalent for islice().
* Documented split of ifilter().

Sets.py:
* Replace old ifilter() usage with new.

Doc/lib/libitertools.tex
Lib/sets.py
Lib/test/test_itertools.py
Modules/itertoolsmodule.c

index 8f6c655506814a50f85001ab64ded0fc953fe645..5e0edf613c0cc457c442ba85cdddbc1a421041a1 100644 (file)
@@ -12,45 +12,43 @@ This module implements a number of iterator building blocks inspired
 by constructs from the Haskell and SML programming languages.  Each
 has been recast in a form suitable for Python.
 
-With the advent of iterators and generators in Python 2.3, each of
-these tools can be expressed easily and succinctly in pure python.
-Rather duplicating what can already be done, this module emphasizes
-providing value in other ways:
-
-\begin{itemize}
-
-    \item Instead of constructing an over-specialized toolset, this module
-        provides basic building blocks that can be readily combined.
-
-        For instance, SML provides a tabulation tool: \code{tabulate(\var{f})}
-        which produces a sequence \code{f(0), f(1), ...}.  This toolbox
-        takes a different approach of providing \function{imap()} and
-        \function{count()} which can be combined to form
-        \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
-        surprising.
-
-        For instance, SML provides a tool:  \code{cycle(\var{seq})} which
-        loops over the sequence elements and then starts again when the
-        sequence is exhausted.  The surprising behavior is the need for
-        significant auxiliary storage (unusual for iterators).  Also, it
-        is trivially implemented in python with almost no performance
-        penalty.
-
-    \item Another source of value comes from standardizing a core set of tools
-        to avoid the readability and reliability problems that arise when many
-        different individuals create their own slightly varying implementations
-        each with their own quirks and naming conventions.
-
-    \item Whether cast in pure python form or C code, tools that use iterators
-        are more memory efficient (and faster) than their list based counterparts.
-        Adopting the principles of just-in-time manufacturing, they create
-        data when and where needed instead of consuming memory with the
-        computer equivalent of ``inventory''.
-
-\end{itemize}
+The module standardizes a core set of fast, memory efficient tools
+that are useful by themselves or in combination.  Standardization helps
+avoid the readability and reliability problems which arise when many
+different individuals create their own slightly varying implementations,
+each with their own quirks and naming conventions.
+
+The tools are designed to combine readily with each another.  This makes
+it easy to construct more specialized tools succinctly and efficiently
+in pure Python.
+
+For instance, SML provides a tabulation tool: \code{tabulate(\var{f})}
+which produces a sequence \code{f(0), f(1), ...}.  This toolbox
+provides \function{imap()} and \function{count()} which can be combined
+to form \code{imap(\var{f}, count())} and produce an equivalent result.
+
+Whether cast in pure python form or C code, tools that use iterators
+are more memory efficient (and faster) than their list based counterparts.
+Adopting the principles of just-in-time manufacturing, they create
+data when and where needed instead of consuming memory with the
+computer equivalent of ``inventory''.
+
+Some tools were omitted from the module because they offered no
+advantage over their pure python counterparts or because their behavior
+was too surprising.
+
+For instance, SML provides a tool:  \code{cycle(\var{seq})} which
+loops over the sequence elements and then starts again when the
+sequence is exhausted.  The surprising behavior is the need for
+significant auxiliary storage (which is unusual for an iterator).
+If needed, the tool is readily constructible using pure Python.
+
+Other tools are being considered for inclusion in future versions of the
+module.  For instance, the function
+\function{chain(\var{it0}, \var{it1}, ...})} would return elements from
+the first iterator until it was exhausted and then move on to each
+successive iterator.  The module author welcomes suggestions for other
+basic building blocks.
 
 \begin{seealso}
   \seetext{The Standard ML Basis Library,
@@ -107,24 +105,36 @@ by functions or loops that truncate the stream.
   \end{verbatim}
 \end{funcdesc}
 
-\begin{funcdesc}{ifilter}{predicate, iterable \optional{, invert}}
+\begin{funcdesc}{ifilter}{predicate, iterable}
   Make an iterator that filters elements from iterable returning only
-  those for which the predicate is \code{True}.  If
-  \var{invert} is \code{True}, then reverse the process and pass through
-  only those elements for which the predicate is \code{False}.
-  If \var{predicate} is \code{None}, return the items that are true
-  (or false if \var{invert} has been set).  Equivalent to:
+  those for which the predicate is \code{True}.
+  If \var{predicate} is \code{None}, return the items that are true.
+  Equivalent to:
 
   \begin{verbatim}
-     def ifilter(predicate, iterable, invert=False):
-         iterable = iter(iterable)
-         while True:
-             x = iterable.next()
-             if predicate is None:
-                  b = bool(x)
-             else:
-                  b = bool(predicate(x))
-             if not invert and b or invert and not b:
+     def ifilter(predicate, iterable):
+         if predicate is None:
+             def predicate(x):
+                 return x
+         for x in iterable:
+             if predicate(x):
+                 yield x
+  \end{verbatim}
+\end{funcdesc}
+
+\begin{funcdesc}{ifilterfalse}{predicate, iterable}
+  Make an iterator that filters elements from iterable returning only
+  those for which the predicate is \code{False}.
+  If \var{predicate} is \code{None}, return the items that are false.
+  Equivalent to:
+
+  \begin{verbatim}
+     def ifilterfalse(predicate, iterable):
+         if predicate is None:
+             def predicate(x):
+                 return x
+         for x in iterable:
+             if not predicate(x):
                  yield x
   \end{verbatim}
 \end{funcdesc}
@@ -169,21 +179,17 @@ by functions or loops that truncate the stream.
 
   \begin{verbatim}
      def islice(iterable, *args):
-         iterable = iter(iterable)
          s = slice(*args)
          next = s.start or 0
          stop = s.stop
          step = s.step or 1
-         cnt = 0
-         while True:
-              while cnt < next:
-                   dummy = iterable.next()
-                   cnt += 1
-              if cnt >= stop:
-                   break
-              yield iterable.next()
-              cnt += 1
-              next += step
+         for cnt, element in enumerate(iterable):
+             if cnt < next:
+                 continue
+             if cnt >= stop:
+                 break
+             yield element
+             next += step
   \end{verbatim}
 \end{funcdesc}
 
@@ -324,6 +330,18 @@ from building blocks.
 
 >>> def nth(iterable, n):
 ...     "Returns the nth item"
-...     return islice(iterable, n, n+1).next()
+...     return list(islice(iterable, n, n+1))
+
+>>> def all(pred, seq):
+...     "Returns True if pred(x) is True for every element in the iterable"
+...     return not nth(ifilterfalse(pred, seq), 0)
+
+>>> def some(pred, seq):
+...     "Returns True if pred(x) is True at least one element in the iterable"
+...     return bool(nth(ifilter(pred, seq), 0))
+
+>>> def no(pred, seq):
+...     "Returns True if pred(x) is False for every element in the iterable"
+...     return not nth(ifilter(pred, seq), 0)
 
 \end{verbatim}
index 4f55515d0d41d80e99c54418c5ec0b0655e9d58a..9604249c6ff36d66b36bad4fc15d1a627367bac0 100644 (file)
@@ -57,7 +57,7 @@ what's tested is actually `z in y'.
 
 
 __all__ = ['BaseSet', 'Set', 'ImmutableSet']
-from itertools import ifilter
+from itertools import ifilter, ifilterfalse
 
 class BaseSet(object):
     """Common base class for mutable and immutable sets."""
@@ -204,9 +204,9 @@ class BaseSet(object):
         value = True
         selfdata = self._data
         otherdata = other._data
-        for elt in ifilter(otherdata.has_key, selfdata, True):
+        for elt in ifilterfalse(otherdata.has_key, selfdata):
             data[elt] = value
-        for elt in ifilter(selfdata.has_key, otherdata, True):
+        for elt in ifilterfalse(selfdata.has_key, otherdata):
             data[elt] = value
         return result
 
@@ -227,7 +227,7 @@ class BaseSet(object):
         result = self.__class__()
         data = result._data
         value = True
-        for elt in ifilter(other._data.has_key, self, True):
+        for elt in ifilterfalse(other._data.has_key, self):
             data[elt] = value
         return result
 
@@ -260,7 +260,7 @@ class BaseSet(object):
         self._binary_sanity_check(other)
         if len(self) > len(other):  # Fast check for obvious cases
             return False
-        for elt in ifilter(other._data.has_key, self, True):
+        for elt in ifilterfalse(other._data.has_key, self):
             return False
         return True
 
@@ -269,7 +269,7 @@ class BaseSet(object):
         self._binary_sanity_check(other)
         if len(self) < len(other):  # Fast check for obvious cases
             return False
-        for elt in ifilter(self._data.has_key, other, True):
+        for elt in ifilterfalse(self._data.has_key, other):
             return False
         return True
 
index cef17188eddf2360713258e09cfbc41b15f2ed2a..09b7d1320bdea5cda7fc522595840bb3ca4962e3 100644 (file)
@@ -13,12 +13,19 @@ class TestBasicOps(unittest.TestCase):
         def isEven(x):
             return x%2==0
         self.assertEqual(list(ifilter(isEven, range(6))), [0,2,4])
-        self.assertEqual(list(ifilter(isEven, range(6), True)), [1,3,5])
         self.assertEqual(list(ifilter(None, [0,1,0,2,0])), [1,2])
         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_ifilterfalse(self):
+        def isEven(x):
+            return x%2==0
+        self.assertEqual(list(ifilterfalse(isEven, range(6))), [1,3,5])
+        self.assertEqual(list(ifilterfalse(None, [0,1,0,2,0])), [0,0,0])
+        self.assertRaises(TypeError, ifilterfalse)
+        self.assertRaises(TypeError, ifilterfalse, 3)
+        self.assertRaises(TypeError, ifilterfalse, isEven, 3)
 
     def test_izip(self):
         ans = [(x,y) for x, y in izip('abc',count())]
@@ -133,7 +140,19 @@ Samuele
 
 >>> def nth(iterable, n):
 ...     "Returns the nth item"
-...     return islice(iterable, n, n+1).next()
+...     return list(islice(iterable, n, n+1))
+
+>>> def all(pred, seq):
+...     "Returns True if pred(x) is True for every element in the iterable"
+...     return not nth(ifilterfalse(pred, seq), 0)
+
+>>> def some(pred, seq):
+...     "Returns True if pred(x) is True at least one element in the iterable"
+...     return bool(nth(ifilter(pred, seq), 0))
+
+>>> def no(pred, seq):
+...     "Returns True if pred(x) is False for every element in the iterable"
+...     return not nth(ifilter(pred, seq), 0)
 
 """
 
index 453b4a2eb34a72e33307dd4767e4d88210504216..e32ef8cfed2a60ae215417fb907a8171359ab532 100644 (file)
@@ -118,11 +118,11 @@ Afterwards, return every element until the iterable is exhausted.");
 PyTypeObject dropwhile_type = {
        PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
-       "itertools.dropwhile",           /* tp_name */
-       sizeof(dropwhileobject),                 /* tp_basicsize */
+       "itertools.dropwhile",          /* tp_name */
+       sizeof(dropwhileobject),        /* tp_basicsize */
        0,                              /* tp_itemsize */
        /* methods */
-       (destructor)dropwhile_dealloc,     /* tp_dealloc */
+       (destructor)dropwhile_dealloc,  /* tp_dealloc */
        0,                              /* tp_print */
        0,                              /* tp_getattr */
        0,                              /* tp_setattr */
@@ -139,13 +139,13 @@ PyTypeObject dropwhile_type = {
        0,                              /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
                Py_TPFLAGS_BASETYPE,    /* tp_flags */
-       dropwhile_doc,                     /* tp_doc */
+       dropwhile_doc,                  /* tp_doc */
        (traverseproc)dropwhile_traverse,    /* tp_traverse */
        0,                              /* tp_clear */
        0,                              /* tp_richcompare */
        0,                              /* tp_weaklistoffset */
-       (getiterfunc)dropwhile_getiter,    /* tp_iter */
-       (iternextfunc)dropwhile_next,      /* tp_iternext */
+       (getiterfunc)dropwhile_getiter, /* tp_iter */
+       (iternextfunc)dropwhile_next,   /* tp_iternext */
        0,                              /* tp_methods */
        0,                              /* tp_members */
        0,                              /* tp_getset */
@@ -156,7 +156,7 @@ PyTypeObject dropwhile_type = {
        0,                              /* tp_dictoffset */
        0,                              /* tp_init */
        PyType_GenericAlloc,            /* tp_alloc */
-       dropwhile_new,                   /* tp_new */
+       dropwhile_new,                  /* tp_new */
        PyObject_GC_Del,                /* tp_free */
 };
 
@@ -271,11 +271,11 @@ predicate evaluates to true for each entry.");
 PyTypeObject takewhile_type = {
        PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
-       "itertools.takewhile",           /* tp_name */
-       sizeof(takewhileobject),                 /* tp_basicsize */
+       "itertools.takewhile",          /* tp_name */
+       sizeof(takewhileobject),        /* tp_basicsize */
        0,                              /* tp_itemsize */
        /* methods */
-       (destructor)takewhile_dealloc,     /* tp_dealloc */
+       (destructor)takewhile_dealloc,  /* tp_dealloc */
        0,                              /* tp_print */
        0,                              /* tp_getattr */
        0,                              /* tp_setattr */
@@ -292,13 +292,13 @@ PyTypeObject takewhile_type = {
        0,                              /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
                Py_TPFLAGS_BASETYPE,    /* tp_flags */
-       takewhile_doc,                     /* tp_doc */
+       takewhile_doc,                  /* tp_doc */
        (traverseproc)takewhile_traverse,    /* tp_traverse */
        0,                              /* tp_clear */
        0,                              /* tp_richcompare */
        0,                              /* tp_weaklistoffset */
-       (getiterfunc)takewhile_getiter,    /* tp_iter */
-       (iternextfunc)takewhile_next,      /* tp_iternext */
+       (getiterfunc)takewhile_getiter, /* tp_iter */
+       (iternextfunc)takewhile_next,   /* tp_iternext */
        0,                              /* tp_methods */
        0,                              /* tp_members */
        0,                              /* tp_getset */
@@ -309,7 +309,7 @@ PyTypeObject takewhile_type = {
        0,                              /* tp_dictoffset */
        0,                              /* tp_init */
        PyType_GenericAlloc,            /* tp_alloc */
-       takewhile_new,                   /* tp_new */
+       takewhile_new,                  /* tp_new */
        PyObject_GC_Del,                /* tp_free */
 };
 
@@ -449,7 +449,7 @@ PyTypeObject islice_type = {
        sizeof(isliceobject),           /* tp_basicsize */
        0,                              /* tp_itemsize */
        /* methods */
-       (destructor)islice_dealloc,       /* tp_dealloc */
+       (destructor)islice_dealloc,     /* tp_dealloc */
        0,                              /* tp_print */
        0,                              /* tp_getattr */
        0,                              /* tp_setattr */
@@ -466,13 +466,13 @@ PyTypeObject islice_type = {
        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 */
+       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 */
+       (getiterfunc)islice_getiter,    /* tp_iter */
+       (iternextfunc)islice_next,      /* tp_iternext */
        0,                              /* tp_methods */
        0,                              /* tp_members */
        0,                              /* tp_getset */
@@ -589,11 +589,11 @@ with a argument tuple taken from the given sequence.");
 PyTypeObject starmap_type = {
        PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
-       "itertools.starmap",             /* tp_name */
-       sizeof(starmapobject),           /* tp_basicsize */
+       "itertools.starmap",            /* tp_name */
+       sizeof(starmapobject),          /* tp_basicsize */
        0,                              /* tp_itemsize */
        /* methods */
-       (destructor)starmap_dealloc,       /* tp_dealloc */
+       (destructor)starmap_dealloc,    /* tp_dealloc */
        0,                              /* tp_print */
        0,                              /* tp_getattr */
        0,                              /* tp_setattr */
@@ -610,13 +610,13 @@ PyTypeObject starmap_type = {
        0,                              /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
                Py_TPFLAGS_BASETYPE,    /* tp_flags */
-       starmap_doc,                       /* tp_doc */
-       (traverseproc)starmap_traverse,    /* tp_traverse */
+       starmap_doc,                    /* tp_doc */
+       (traverseproc)starmap_traverse, /* tp_traverse */
        0,                              /* tp_clear */
        0,                              /* tp_richcompare */
        0,                              /* tp_weaklistoffset */
-       (getiterfunc)starmap_getiter,      /* tp_iter */
-       (iternextfunc)starmap_next,        /* tp_iternext */
+       (getiterfunc)starmap_getiter,   /* tp_iter */
+       (iternextfunc)starmap_next,     /* tp_iternext */
        0,                              /* tp_methods */
        0,                              /* tp_members */
        0,                              /* tp_getset */
@@ -627,7 +627,7 @@ PyTypeObject starmap_type = {
        0,                              /* tp_dictoffset */
        0,                              /* tp_init */
        PyType_GenericAlloc,            /* tp_alloc */
-       starmap_new,                     /* tp_new */
+       starmap_new,                    /* tp_new */
        PyObject_GC_Del,                /* tp_free */
 };
 
@@ -783,8 +783,8 @@ iterables.");
 PyTypeObject imap_type = {
        PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
-       "itertools.imap",             /* tp_name */
-       sizeof(imapobject),           /* tp_basicsize */
+       "itertools.imap",               /* tp_name */
+       sizeof(imapobject),             /* tp_basicsize */
        0,                              /* tp_itemsize */
        /* methods */
        (destructor)imap_dealloc,       /* tp_dealloc */
@@ -821,7 +821,7 @@ PyTypeObject imap_type = {
        0,                              /* tp_dictoffset */
        0,                              /* tp_init */
        PyType_GenericAlloc,            /* tp_alloc */
-       imap_new,                     /* tp_new */
+       imap_new,                       /* tp_new */
        PyObject_GC_Del,                /* tp_free */
 };
 
@@ -908,8 +908,8 @@ instances of obj (default is None).");
 PyTypeObject times_type = {
        PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
-       "itertools.times",             /* tp_name */
-       sizeof(timesobject),           /* tp_basicsize */
+       "itertools.times",              /* tp_name */
+       sizeof(timesobject),            /* tp_basicsize */
        0,                              /* tp_itemsize */
        /* methods */
        (destructor)times_dealloc,      /* tp_dealloc */
@@ -929,13 +929,13 @@ PyTypeObject times_type = {
        0,                              /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
                Py_TPFLAGS_BASETYPE,    /* tp_flags */
-       times_doc,                       /* tp_doc */
+       times_doc,                      /* tp_doc */
        (traverseproc)times_traverse,   /* tp_traverse */
        0,                              /* tp_clear */
        0,                              /* tp_richcompare */
        0,                              /* tp_weaklistoffset */
-       (getiterfunc)times_getiter,      /* tp_iter */
-       (iternextfunc)times_next,        /* tp_iternext */
+       (getiterfunc)times_getiter,     /* tp_iter */
+       (iternextfunc)times_next,       /* tp_iternext */
        0,                              /* tp_methods */
        0,                              /* tp_members */
        0,                              /* tp_getset */
@@ -957,7 +957,6 @@ typedef struct {
        PyObject_HEAD
        PyObject *func;
        PyObject *it;
-       long     invert;
 } ifilterobject;
 
 PyTypeObject ifilter_type;
@@ -965,17 +964,13 @@ PyTypeObject ifilter_type;
 static PyObject *
 ifilter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
-       PyObject *func, *seq, *invert=NULL;
+       PyObject *func, *seq;
        PyObject *it;
        ifilterobject *lz;
-       long inv=0;
 
-       if (!PyArg_UnpackTuple(args, "ifilter", 2, 3, &func, &seq, &invert))
+       if (!PyArg_UnpackTuple(args, "ifilter", 2, 2, &func, &seq))
                return NULL;
 
-       if (invert != NULL  &&  PyObject_IsTrue(invert))
-               inv = 1;
-
        /* Get iterator. */
        it = PyObject_GetIter(seq);
        if (it == NULL)
@@ -990,7 +985,6 @@ ifilter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
        Py_INCREF(func);
        lz->func = func;
        lz->it = it;
-       lz->invert = inv;
 
        return (PyObject *)lz;
 }
@@ -1046,7 +1040,7 @@ ifilter_next(ifilterobject *lz)
                        ok = PyObject_IsTrue(good);
                        Py_DECREF(good);
                }
-               if (ok ^ lz->invert)
+               if (ok)
                        return item;
                Py_DECREF(item);
        }
@@ -1060,20 +1054,173 @@ ifilter_getiter(PyObject *lz)
 }
 
 PyDoc_STRVAR(ifilter_doc,
-"ifilter(function or None, sequence [, invert]) --> ifilter object\n\
+"ifilter(function or None, sequence) --> ifilter object\n\
 \n\
-Return those items of sequence for which function(item) is true.  If\n\
-invert is set to True, return items for which function(item) if False.\n\
-If function is None, return the items that are true (unless invert is set).");
+Return those items of sequence for which function(item) is true.\n\
+If function is None, return the items that are true.");
 
 PyTypeObject ifilter_type = {
        PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
-       "itertools.ifilter",             /* tp_name */
-       sizeof(ifilterobject),           /* tp_basicsize */
+       "itertools.ifilter",            /* tp_name */
+       sizeof(ifilterobject),          /* tp_basicsize */
+       0,                              /* tp_itemsize */
+       /* methods */
+       (destructor)ifilter_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 */
+       ifilter_doc,                    /* tp_doc */
+       (traverseproc)ifilter_traverse, /* tp_traverse */
+       0,                              /* tp_clear */
+       0,                              /* tp_richcompare */
+       0,                              /* tp_weaklistoffset */
+       (getiterfunc)ifilter_getiter,   /* tp_iter */
+       (iternextfunc)ifilter_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 */
+       ifilter_new,                    /* tp_new */
+       PyObject_GC_Del,                /* tp_free */
+};
+
+
+/* ifilterfalse object ************************************************************/
+
+typedef struct {
+       PyObject_HEAD
+       PyObject *func;
+       PyObject *it;
+} ifilterfalseobject;
+
+PyTypeObject ifilterfalse_type;
+
+static PyObject *
+ifilterfalse_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *func, *seq, *invert=NULL;
+       PyObject *it;
+       ifilterfalseobject *lz;
+
+       if (!PyArg_UnpackTuple(args, "ifilterfalse", 2, 2, &func, &seq))
+               return NULL;
+
+       /* Get iterator. */
+       it = PyObject_GetIter(seq);
+       if (it == NULL)
+               return NULL;
+
+       /* create ifilterfalseobject structure */
+       lz = (ifilterfalseobject *)type->tp_alloc(type, 0);
+       if (lz == NULL) {
+               Py_DECREF(it);
+               return NULL;
+       }
+       Py_INCREF(func);
+       lz->func = func;
+       lz->it = it;
+
+       return (PyObject *)lz;
+}
+
+static void
+ifilterfalse_dealloc(ifilterfalseobject *lz)
+{
+       PyObject_GC_UnTrack(lz);
+       Py_XDECREF(lz->func);
+       Py_XDECREF(lz->it);
+       lz->ob_type->tp_free(lz);
+}
+
+static int
+ifilterfalse_traverse(ifilterfalseobject *lz, visitproc visit, void *arg)
+{
+       int err;
+
+       if (lz->it) {
+               err = visit(lz->it, arg);
+               if (err)
+                       return err;
+       }
+       if (lz->func) {
+               err = visit(lz->func, arg);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+static PyObject *
+ifilterfalse_next(ifilterfalseobject *lz)
+{
+       PyObject *item;
+       long ok;
+
+       for (;;) {
+               item = PyIter_Next(lz->it);
+               if (item == NULL)
+                       return NULL;
+
+               if (lz->func == Py_None) {
+                       ok = PyObject_IsTrue(item);
+               } else {
+                       PyObject *good;
+                       good = PyObject_CallFunctionObjArgs(lz->func,
+                                                           item, NULL);
+                       if (good == NULL) {
+                               Py_DECREF(item);
+                               return NULL;
+                       }
+                       ok = PyObject_IsTrue(good);
+                       Py_DECREF(good);
+               }
+               if (!ok)
+                       return item;
+               Py_DECREF(item);
+       }
+}
+
+static PyObject *
+ifilterfalse_getiter(PyObject *lz)
+{
+       Py_INCREF(lz);
+       return lz;
+}
+
+PyDoc_STRVAR(ifilterfalse_doc,
+"ifilterfalse(function or None, sequence) --> ifilterfalse object\n\
+\n\
+Return those items of sequence for which function(item) is false.\n\
+If function is None, return the items that are false.");
+
+PyTypeObject ifilterfalse_type = {
+       PyObject_HEAD_INIT(NULL)
+       0,                              /* ob_size */
+       "itertools.ifilterfalse",       /* tp_name */
+       sizeof(ifilterfalseobject),     /* tp_basicsize */
        0,                              /* tp_itemsize */
        /* methods */
-       (destructor)ifilter_dealloc,       /* tp_dealloc */
+       (destructor)ifilterfalse_dealloc,       /* tp_dealloc */
        0,                              /* tp_print */
        0,                              /* tp_getattr */
        0,                              /* tp_setattr */
@@ -1090,13 +1237,13 @@ PyTypeObject ifilter_type = {
        0,                              /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
                Py_TPFLAGS_BASETYPE,    /* tp_flags */
-       ifilter_doc,                       /* tp_doc */
-       (traverseproc)ifilter_traverse,    /* tp_traverse */
+       ifilterfalse_doc,               /* tp_doc */
+       (traverseproc)ifilterfalse_traverse,    /* tp_traverse */
        0,                              /* tp_clear */
        0,                              /* tp_richcompare */
        0,                              /* tp_weaklistoffset */
-       (getiterfunc)ifilter_getiter,      /* tp_iter */
-       (iternextfunc)ifilter_next,        /* tp_iternext */
+       (getiterfunc)ifilterfalse_getiter,      /* tp_iter */
+       (iternextfunc)ifilterfalse_next,        /* tp_iternext */
        0,                              /* tp_methods */
        0,                              /* tp_members */
        0,                              /* tp_getset */
@@ -1107,7 +1254,7 @@ PyTypeObject ifilter_type = {
        0,                              /* tp_dictoffset */
        0,                              /* tp_init */
        PyType_GenericAlloc,            /* tp_alloc */
-       ifilter_new,                     /* tp_new */
+       ifilterfalse_new,               /* tp_new */
        PyObject_GC_Del,                /* tp_free */
 };
 
@@ -1161,8 +1308,8 @@ integers starting from zero or, if specified, from firstval.");
 PyTypeObject count_type = {
        PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
-       "itertools.count",             /* tp_name */
-       sizeof(countobject),           /* tp_basicsize */
+       "itertools.count",              /* tp_name */
+       sizeof(countobject),            /* tp_basicsize */
        0,                              /* tp_itemsize */
        /* methods */
        (destructor)PyObject_Del,       /* tp_dealloc */
@@ -1181,13 +1328,13 @@ PyTypeObject count_type = {
        0,                              /* tp_setattro */
        0,                              /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT,             /* tp_flags */
-       count_doc,                       /* tp_doc */
+       count_doc,                      /* tp_doc */
        0,                              /* tp_traverse */
        0,                              /* tp_clear */
        0,                              /* tp_richcompare */
        0,                              /* tp_weaklistoffset */
-       (getiterfunc)count_getiter,      /* tp_iter */
-       (iternextfunc)count_next,        /* tp_iternext */
+       (getiterfunc)count_getiter,     /* tp_iter */
+       (iternextfunc)count_next,       /* tp_iternext */
        0,                              /* tp_methods */
        0,                              /* tp_members */
        0,                              /* tp_getset */
@@ -1349,11 +1496,11 @@ a list.");
 PyTypeObject izip_type = {
        PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
-       "itertools.izip",                /* tp_name */
-       sizeof(izipobject),              /* tp_basicsize */
+       "itertools.izip",               /* tp_name */
+       sizeof(izipobject),             /* tp_basicsize */
        0,                              /* tp_itemsize */
        /* methods */
-       (destructor)izip_dealloc,          /* tp_dealloc */
+       (destructor)izip_dealloc,       /* tp_dealloc */
        0,                              /* tp_print */
        0,                              /* tp_getattr */
        0,                              /* tp_setattr */
@@ -1370,13 +1517,13 @@ PyTypeObject izip_type = {
        0,                              /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
                Py_TPFLAGS_BASETYPE,    /* tp_flags */
-       izip_doc,                          /* tp_doc */
+       izip_doc,                       /* tp_doc */
        (traverseproc)izip_traverse,    /* tp_traverse */
        0,                              /* tp_clear */
        0,                              /* tp_richcompare */
        0,                              /* tp_weaklistoffset */
-       (getiterfunc)izip_getiter,         /* tp_iter */
-       (iternextfunc)izip_next,           /* tp_iternext */
+       (getiterfunc)izip_getiter,      /* tp_iter */
+       (iternextfunc)izip_next,        /* tp_iternext */
        0,                              /* tp_methods */
        0,                              /* tp_members */
        0,                              /* tp_getset */
@@ -1387,7 +1534,7 @@ PyTypeObject izip_type = {
        0,                              /* tp_dictoffset */
        0,                              /* tp_init */
        PyType_GenericAlloc,            /* tp_alloc */
-       izip_new,                        /* tp_new */
+       izip_new,                       /* tp_new */
        PyObject_GC_Del,                /* tp_free */
 };
 
@@ -1458,7 +1605,7 @@ PyTypeObject repeat_type = {
        sizeof(repeatobject),           /* tp_basicsize */
        0,                              /* tp_itemsize */
        /* methods */
-       (destructor)repeat_dealloc,       /* tp_dealloc */
+       (destructor)repeat_dealloc,     /* tp_dealloc */
        0,                              /* tp_print */
        0,                              /* tp_getattr */
        0,                              /* tp_setattr */
@@ -1475,13 +1622,13 @@ PyTypeObject repeat_type = {
        0,                              /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
                Py_TPFLAGS_BASETYPE,    /* tp_flags */
-       repeat_doc,                       /* tp_doc */
-       (traverseproc)repeat_traverse,    /* tp_traverse */
+       repeat_doc,                     /* tp_doc */
+       (traverseproc)repeat_traverse,  /* tp_traverse */
        0,                              /* tp_clear */
        0,                              /* tp_richcompare */
        0,                              /* tp_weaklistoffset */
-       (getiterfunc)repeat_getiter,      /* tp_iter */
-       (iternextfunc)repeat_next,        /* tp_iternext */
+       (getiterfunc)repeat_getiter,    /* tp_iter */
+       (iternextfunc)repeat_next,      /* tp_iternext */
        0,                              /* tp_methods */
        0,                              /* tp_members */
        0,                              /* tp_getset */
@@ -1508,8 +1655,8 @@ repeat(elem) --> elem, elem, elem, ...\n\
 \n\
 Iterators terminating on the shortest input sequence:\n\
 izip(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ... \n\
-ifilter(pred, seq, invert=False) --> elements of seq where\n\
-       pred(elem) is True (or False if invert is set)\n\
+ifilter(pred, seq) --> elements of seq where pred(elem) is True\n\
+ifilterfalse(pred, seq) --> elements of seq where pred(elem) is False\n\
 islice(seq, [start,] stop [, step]) --> elements from\n\
        seq[start:stop:step]\n\
 imap(fun, p, q, ...) --> fun(p0, q0), fun(p1, q1), ...\n\
@@ -1523,56 +1670,33 @@ dropwhile(pred, seq) --> seq[n], seq[n+1], starting when pred fails\n\
 PyMODINIT_FUNC
 inititertools(void)
 {
+       int i;
        PyObject *m;
+       char *name;
+       PyTypeObject *typelist[] = {
+               &dropwhile_type,
+               &takewhile_type,
+               &islice_type,
+               &starmap_type,
+               &imap_type,
+               &times_type,
+               &ifilter_type,
+               &ifilterfalse_type,
+               &count_type,
+               &izip_type,
+               &repeat_type,
+               NULL
+       };
+
        m = Py_InitModule3("itertools", NULL, module_doc);
 
-       PyModule_AddObject(m, "dropwhile", (PyObject *)&dropwhile_type);
-       if (PyType_Ready(&dropwhile_type) < 0)
-               return;
-       Py_INCREF(&dropwhile_type);
-
-       PyModule_AddObject(m, "takewhile", (PyObject *)&takewhile_type);
-       if (PyType_Ready(&takewhile_type) < 0)
-               return;
-       Py_INCREF(&takewhile_type);
-
-       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);
-       if (PyType_Ready(&starmap_type) < 0)
-               return;
-       Py_INCREF(&starmap_type);
-
-       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)
-               return;
-       Py_INCREF(&ifilter_type);
-       PyModule_AddObject(m, "ifilter", (PyObject *)&ifilter_type);
-
-       if (PyType_Ready(&count_type) < 0)
-               return;
-       Py_INCREF(&count_type);
-       PyModule_AddObject(m, "count", (PyObject *)&count_type);
-
-       if (PyType_Ready(&izip_type) < 0)
-               return;
-       Py_INCREF(&izip_type);
-       PyModule_AddObject(m, "izip", (PyObject *)&izip_type);
-
-       if (PyType_Ready(&repeat_type) < 0)
-               return;
-       Py_INCREF(&repeat_type);
-       PyModule_AddObject(m, "repeat", (PyObject *)&repeat_type);
+       for (i=0 ; typelist[i] != NULL ; i++) {
+               if (PyType_Ready(typelist[i]) < 0)
+                       return;
+               name = strchr(typelist[i]->tp_name, '.') + 1;
+               if (name == NULL)
+                       return;
+               Py_INCREF(typelist[i]);
+               PyModule_AddObject(m, name, (PyObject *)typelist[i]);
+       }
 }