Kaydet (Commit) 61fe64d5 authored tarafından Raymond Hettinger's avatar Raymond Hettinger

User requested changes to the itertools module.

Subsumed times() into repeat().
Added cycle() and chain().
üst c85b6a2d
...@@ -33,22 +33,8 @@ Adopting the principles of just-in-time manufacturing, they create ...@@ -33,22 +33,8 @@ Adopting the principles of just-in-time manufacturing, they create
data when and where needed instead of consuming memory with the data when and where needed instead of consuming memory with the
computer equivalent of ``inventory''. computer equivalent of ``inventory''.
Some tools were omitted from the module because they offered no The module author welcomes suggestions for other basic building blocks
advantage over their pure python counterparts or because their behavior to be added to future versions of the module.
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} \begin{seealso}
\seetext{The Standard ML Basis Library, \seetext{The Standard ML Basis Library,
...@@ -67,6 +53,20 @@ The following module functions all construct and return iterators. ...@@ -67,6 +53,20 @@ The following module functions all construct and return iterators.
Some provide streams of infinite length, so they should only be accessed Some provide streams of infinite length, so they should only be accessed
by functions or loops that truncate the stream. by functions or loops that truncate the stream.
\begin{funcdesc}{chain}{*iterables}
Make an iterator that returns elements from the first iterable until
it is exhausted, then proceeds to the next iterable, until all of the
iterables are exhausted. Used for treating consecutive sequences as
a single sequence. Equivalent to:
\begin{verbatim}
def chain(*iterables):
for it in iterables:
for element in it:
yield element
\end{verbatim}
\end{funcdesc}
\begin{funcdesc}{count}{\optional{n}} \begin{funcdesc}{count}{\optional{n}}
Make an iterator that returns consecutive integers starting with \var{n}. Make an iterator that returns consecutive integers starting with \var{n}.
Does not currently support python long integers. Often used as an Does not currently support python long integers. Often used as an
...@@ -85,6 +85,29 @@ by functions or loops that truncate the stream. ...@@ -85,6 +85,29 @@ by functions or loops that truncate the stream.
may change in the future. may change in the future.
\end{funcdesc} \end{funcdesc}
\begin{funcdesc}{cycle}{iterable}
Make an iterator returning elements from the iterable and saving a
copy of each. When the iterable is exhausted, return elements from
the saved copy. Repeats indefinitely. Equivalent to:
\begin{verbatim}
def cycle(iterable):
saved = []
for element in iterable:
yield element
saved.append(element)
if len(saved) == 0:
return
while True:
for element in saved:
yield element
\end{verbatim}
Note, this is the only member of the toolkit that may require
significant auxiliary storage (depending on the length of the
iterable.
\end{funcdesc}
\begin{funcdesc}{dropwhile}{predicate, iterable} \begin{funcdesc}{dropwhile}{predicate, iterable}
Make an iterator that drops elements from the iterable as long as Make an iterator that drops elements from the iterable as long as
the predicate is true; afterwards, returns every element. Note, the predicate is true; afterwards, returns every element. Note,
...@@ -207,16 +230,21 @@ by functions or loops that truncate the stream. ...@@ -207,16 +230,21 @@ by functions or loops that truncate the stream.
\end{verbatim} \end{verbatim}
\end{funcdesc} \end{funcdesc}
\begin{funcdesc}{repeat}{object} \begin{funcdesc}{repeat}{object\optional{, times}}
Make an iterator that returns \var{object} over and over again. Make an iterator that returns \var{object} over and over again.
Runs indefinitely unless the \var{times} argument is specified.
Used as argument to \function{imap()} for invariant parameters Used as argument to \function{imap()} for invariant parameters
to the called function. Also used with \function{izip()} to create to the called function. Also used with \function{izip()} to create
an invariant part of a tuple record. Equivalent to: an invariant part of a tuple record. Equivalent to:
\begin{verbatim} \begin{verbatim}
def repeat(object): def repeat(object, times=None):
while True: if times is None:
yield object while True:
yield object
else:
for i in xrange(times):
yield object
\end{verbatim} \end{verbatim}
\end{funcdesc} \end{funcdesc}
...@@ -253,20 +281,6 @@ by functions or loops that truncate the stream. ...@@ -253,20 +281,6 @@ by functions or loops that truncate the stream.
\end{verbatim} \end{verbatim}
\end{funcdesc} \end{funcdesc}
\begin{funcdesc}{times}{n, \optional{object}}
Make an iterator that returns \var{object} \var{n} times.
\var{object} defaults to \code{None}. Used for looping a specific
number of times without creating a number object on each pass.
Equivalent to:
\begin{verbatim}
def times(n, object=None):
if n<0 : raise ValueError
for i in xrange(n):
yield object
\end{verbatim}
\end{funcdesc}
\subsection{Examples \label{itertools-example}} \subsection{Examples \label{itertools-example}}
...@@ -274,12 +288,6 @@ The following examples show common uses for each tool and ...@@ -274,12 +288,6 @@ The following examples show common uses for each tool and
demonstrate ways they can be combined. demonstrate ways they can be combined.
\begin{verbatim} \begin{verbatim}
>>> for i in times(3):
... print "Hello"
...
Hello
Hello
Hello
>>> amounts = [120.15, 764.05, 823.14] >>> amounts = [120.15, 764.05, 823.14]
>>> for checknum, amount in izip(count(1200), amounts): >>> for checknum, amount in izip(count(1200), amounts):
...@@ -343,4 +351,8 @@ from building blocks. ...@@ -343,4 +351,8 @@ from building blocks.
... "Returns True if pred(x) is False for every element in the iterable" ... "Returns True if pred(x) is False for every element in the iterable"
... return not nth(ifilter(pred, seq), 0) ... return not nth(ifilter(pred, seq), 0)
>>> def pairwise(seq):
... "s -> (s0,s1), (s1,s2), (s2, s3), ..."
... return izip(seq, islice(seq,1,len(seq)))
\end{verbatim} \end{verbatim}
...@@ -4,11 +4,18 @@ from itertools import * ...@@ -4,11 +4,18 @@ from itertools import *
import sys import sys
class TestBasicOps(unittest.TestCase): class TestBasicOps(unittest.TestCase):
def test_chain(self):
self.assertEqual(list(chain('abc', 'def')), list('abcdef'))
def test_count(self): def test_count(self):
self.assertEqual(zip('abc',count()), [('a', 0), ('b', 1), ('c', 2)]) self.assertEqual(zip('abc',count()), [('a', 0), ('b', 1), ('c', 2)])
self.assertEqual(zip('abc',count(3)), [('a', 3), ('b', 4), ('c', 5)]) self.assertEqual(zip('abc',count(3)), [('a', 3), ('b', 4), ('c', 5)])
self.assertRaises(TypeError, count, 2, 3) self.assertRaises(TypeError, count, 2, 3)
def test_cycle(self):
self.assertEqual(list(islice(cycle('abc'),10)), list('abcabcabca'))
self.assertEqual(list(cycle('')), [])
def test_ifilter(self): def test_ifilter(self):
def isEven(x): def isEven(x):
return x%2==0 return x%2==0
...@@ -35,13 +42,9 @@ class TestBasicOps(unittest.TestCase): ...@@ -35,13 +42,9 @@ class TestBasicOps(unittest.TestCase):
def test_repeat(self): def test_repeat(self):
self.assertEqual(zip(xrange(3),repeat('a')), self.assertEqual(zip(xrange(3),repeat('a')),
[(0, 'a'), (1, 'a'), (2, 'a')]) [(0, 'a'), (1, 'a'), (2, 'a')])
self.assertEqual(list(repeat('a', 3)), ['a', 'a', 'a'])
self.assertRaises(TypeError, repeat) self.assertRaises(TypeError, repeat)
def test_times(self):
self.assertEqual(list(times(3)), [None]*3)
self.assertEqual(list(times(3, True)), [True]*3)
self.assertRaises(ValueError, times, -1)
def test_imap(self): def test_imap(self):
import operator import operator
self.assertEqual(list(imap(operator.pow, range(3), range(1,7))), self.assertEqual(list(imap(operator.pow, range(3), range(1,7))),
...@@ -94,12 +97,6 @@ class TestBasicOps(unittest.TestCase): ...@@ -94,12 +97,6 @@ class TestBasicOps(unittest.TestCase):
libreftest = """ Doctest for examples in the library reference, libitertools.tex libreftest = """ Doctest for examples in the library reference, libitertools.tex
>>> for i in times(3):
... print "Hello"
...
Hello
Hello
Hello
>>> amounts = [120.15, 764.05, 823.14] >>> amounts = [120.15, 764.05, 823.14]
>>> for checknum, amount in izip(count(1200), amounts): >>> for checknum, amount in izip(count(1200), amounts):
...@@ -154,6 +151,10 @@ Samuele ...@@ -154,6 +151,10 @@ Samuele
... "Returns True if pred(x) is False for every element in the iterable" ... "Returns True if pred(x) is False for every element in the iterable"
... return not nth(ifilter(pred, seq), 0) ... return not nth(ifilter(pred, seq), 0)
>>> def pairwise(seq):
... "s -> (s0,s1), (s1,s2), (s2, s3), ..."
... return izip(seq, islice(seq,1,len(seq)))
""" """
__test__ = {'libreftest' : libreftest} __test__ = {'libreftest' : libreftest}
......
...@@ -17,7 +17,9 @@ TBD ...@@ -17,7 +17,9 @@ TBD
Extension modules Extension modules
----------------- -----------------
TBD - Made user requested changes to the itertools module.
Subsumed the times() function into repeat().
Added chain() and cycle().
Library Library
------- -------
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment