mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
User requested changes to the itertools module.
Subsumed times() into repeat(). Added cycle() and chain().
This commit is contained in:
parent
c85b6a2d4d
commit
61fe64d5de
4 changed files with 303 additions and 104 deletions
|
@ -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.
|
||||||
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.
|
||||||
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.
|
||||||
\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.
|
||||||
\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
|
||||||
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.
|
||||||
... "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 *
|
||||||
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):
|
||||||
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):
|
||||||
|
|
||||||
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
|
||||||
... "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
|
||||||
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
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -7,6 +7,163 @@
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* cycle object **********************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
PyObject *it;
|
||||||
|
PyObject *saved;
|
||||||
|
int firstpass;
|
||||||
|
} cycleobject;
|
||||||
|
|
||||||
|
PyTypeObject cycle_type;
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
cycle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
PyObject *it;
|
||||||
|
PyObject *iterable;
|
||||||
|
PyObject *saved;
|
||||||
|
cycleobject *lz;
|
||||||
|
|
||||||
|
if (!PyArg_UnpackTuple(args, "cycle", 1, 1, &iterable))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Get iterator. */
|
||||||
|
it = PyObject_GetIter(iterable);
|
||||||
|
if (it == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
saved = PyList_New(0);
|
||||||
|
if (saved == NULL) {
|
||||||
|
Py_DECREF(it);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create cycleobject structure */
|
||||||
|
lz = (cycleobject *)type->tp_alloc(type, 0);
|
||||||
|
if (lz == NULL) {
|
||||||
|
Py_DECREF(it);
|
||||||
|
Py_DECREF(saved);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
lz->it = it;
|
||||||
|
lz->saved = saved;
|
||||||
|
lz->firstpass = 0;
|
||||||
|
|
||||||
|
return (PyObject *)lz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cycle_dealloc(cycleobject *lz)
|
||||||
|
{
|
||||||
|
PyObject_GC_UnTrack(lz);
|
||||||
|
Py_XDECREF(lz->saved);
|
||||||
|
Py_XDECREF(lz->it);
|
||||||
|
lz->ob_type->tp_free(lz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cycle_traverse(cycleobject *lz, visitproc visit, void *arg)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (lz->it) {
|
||||||
|
err = visit(lz->it, arg);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (lz->saved) {
|
||||||
|
err = visit(lz->saved, arg);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
cycle_next(cycleobject *lz)
|
||||||
|
{
|
||||||
|
PyObject *item;
|
||||||
|
PyObject *it;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
item = PyIter_Next(lz->it);
|
||||||
|
if (item != NULL) {
|
||||||
|
if (!lz->firstpass)
|
||||||
|
PyList_Append(lz->saved, item);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
if (PyList_Size(lz->saved) == 0)
|
||||||
|
return NULL;
|
||||||
|
it = PyObject_GetIter(lz->saved);
|
||||||
|
if (it == NULL)
|
||||||
|
return NULL;
|
||||||
|
Py_DECREF(lz->it);
|
||||||
|
lz->it = it;
|
||||||
|
lz->firstpass = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
cycle_getiter(PyObject *lz)
|
||||||
|
{
|
||||||
|
Py_INCREF(lz);
|
||||||
|
return lz;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(cycle_doc,
|
||||||
|
"cycle(iterable) --> cycle object\n\
|
||||||
|
\n\
|
||||||
|
Return elements from the iterable until it is exhausted.\n\
|
||||||
|
Then repeat the sequence indefinitely.");
|
||||||
|
|
||||||
|
PyTypeObject cycle_type = {
|
||||||
|
PyObject_HEAD_INIT(NULL)
|
||||||
|
0, /* ob_size */
|
||||||
|
"itertools.cycle", /* tp_name */
|
||||||
|
sizeof(cycleobject), /* tp_basicsize */
|
||||||
|
0, /* tp_itemsize */
|
||||||
|
/* methods */
|
||||||
|
(destructor)cycle_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 */
|
||||||
|
cycle_doc, /* tp_doc */
|
||||||
|
(traverseproc)cycle_traverse, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
(getiterfunc)cycle_getiter, /* tp_iter */
|
||||||
|
(iternextfunc)cycle_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 */
|
||||||
|
cycle_new, /* tp_new */
|
||||||
|
PyObject_GC_Del, /* tp_free */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* dropwhile object **********************************************************/
|
/* dropwhile object **********************************************************/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -826,93 +983,110 @@ PyTypeObject imap_type = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* times object ************************************************************/
|
/* chain object ************************************************************/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
PyObject *obj;
|
long tuplesize;
|
||||||
long cnt;
|
long iternum; /* which iterator is active */
|
||||||
} timesobject;
|
PyObject *ittuple; /* tuple of iterators */
|
||||||
|
} chainobject;
|
||||||
|
|
||||||
PyTypeObject times_type;
|
PyTypeObject chain_type;
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
times_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
chain_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
timesobject *lz;
|
chainobject *lz;
|
||||||
PyObject *obj = Py_None;
|
int tuplesize = PySequence_Length(args);
|
||||||
long cnt;
|
int i;
|
||||||
|
PyObject *ittuple;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "l|O:times", &cnt, &obj))
|
/* obtain iterators */
|
||||||
return NULL;
|
assert(PyTuple_Check(args));
|
||||||
|
ittuple = PyTuple_New(tuplesize);
|
||||||
if (cnt < 0) {
|
if(ittuple == NULL)
|
||||||
PyErr_SetString(PyExc_ValueError,
|
|
||||||
"count for times() cannot be negative.");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
for (i=0; i < tuplesize; ++i) {
|
||||||
|
PyObject *item = PyTuple_GET_ITEM(args, i);
|
||||||
|
PyObject *it = PyObject_GetIter(item);
|
||||||
|
if (it == NULL) {
|
||||||
|
if (PyErr_ExceptionMatches(PyExc_TypeError))
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"chain argument #%d must support iteration",
|
||||||
|
i+1);
|
||||||
|
Py_DECREF(ittuple);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyTuple_SET_ITEM(ittuple, i, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create timesobject structure */
|
/* create chainobject structure */
|
||||||
lz = (timesobject *)type->tp_alloc(type, 0);
|
lz = (chainobject *)type->tp_alloc(type, 0);
|
||||||
if (lz == NULL)
|
if (lz == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
lz->cnt = cnt;
|
|
||||||
Py_INCREF(obj);
|
lz->ittuple = ittuple;
|
||||||
lz->obj = obj;
|
lz->iternum = 0;
|
||||||
|
lz->tuplesize = tuplesize;
|
||||||
|
|
||||||
return (PyObject *)lz;
|
return (PyObject *)lz;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
times_dealloc(timesobject *lz)
|
chain_dealloc(chainobject *lz)
|
||||||
{
|
{
|
||||||
PyObject_GC_UnTrack(lz);
|
PyObject_GC_UnTrack(lz);
|
||||||
Py_XDECREF(lz->obj);
|
Py_XDECREF(lz->ittuple);
|
||||||
lz->ob_type->tp_free(lz);
|
lz->ob_type->tp_free(lz);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
times_traverse(timesobject *lz, visitproc visit, void *arg)
|
chain_traverse(chainobject *lz, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
if (lz->obj)
|
if (lz->ittuple)
|
||||||
return visit(lz->obj, arg);
|
return visit(lz->ittuple, arg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
times_next(timesobject *lz)
|
chain_next(chainobject *lz)
|
||||||
{
|
{
|
||||||
PyObject *obj = lz->obj;
|
PyObject *it;
|
||||||
|
PyObject *item;
|
||||||
|
|
||||||
if (lz->cnt > 0) {
|
while (lz->iternum < lz->tuplesize) {
|
||||||
lz->cnt--;
|
it = PyTuple_GET_ITEM(lz->ittuple, lz->iternum);
|
||||||
Py_INCREF(obj);
|
item = PyIter_Next(it);
|
||||||
return obj;
|
if (item != NULL)
|
||||||
|
return item;
|
||||||
|
lz->iternum++;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
times_getiter(PyObject *lz)
|
chain_getiter(PyObject *lz)
|
||||||
{
|
{
|
||||||
Py_INCREF(lz);
|
Py_INCREF(lz);
|
||||||
return lz;
|
return lz;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(times_doc,
|
PyDoc_STRVAR(chain_doc,
|
||||||
"times(n [,obj]) --> times object\n\
|
"chain(*iterables) --> chain object\n\
|
||||||
\n\
|
\n\
|
||||||
Return a times object whose .next() method returns n consecutive\n\
|
Return a chain object whose .next() method returns elements from the\n\
|
||||||
instances of obj (default is None).");
|
first iterable until it is exhausted, then elements from the next\n\
|
||||||
|
iterable, until all of the iterables are exhausted.");
|
||||||
|
|
||||||
PyTypeObject times_type = {
|
PyTypeObject chain_type = {
|
||||||
PyObject_HEAD_INIT(NULL)
|
PyObject_HEAD_INIT(NULL)
|
||||||
0, /* ob_size */
|
0, /* ob_size */
|
||||||
"itertools.times", /* tp_name */
|
"itertools.chain", /* tp_name */
|
||||||
sizeof(timesobject), /* tp_basicsize */
|
sizeof(chainobject), /* tp_basicsize */
|
||||||
0, /* tp_itemsize */
|
0, /* tp_itemsize */
|
||||||
/* methods */
|
/* methods */
|
||||||
(destructor)times_dealloc, /* tp_dealloc */
|
(destructor)chain_dealloc, /* tp_dealloc */
|
||||||
0, /* tp_print */
|
0, /* tp_print */
|
||||||
0, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
0, /* tp_setattr */
|
0, /* tp_setattr */
|
||||||
|
@ -929,13 +1103,13 @@ PyTypeObject times_type = {
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
||||||
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
times_doc, /* tp_doc */
|
chain_doc, /* tp_doc */
|
||||||
(traverseproc)times_traverse, /* tp_traverse */
|
(traverseproc)chain_traverse, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
0, /* tp_richcompare */
|
0, /* tp_richcompare */
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
(getiterfunc)times_getiter, /* tp_iter */
|
(getiterfunc)chain_getiter, /* tp_iter */
|
||||||
(iternextfunc)times_next, /* tp_iternext */
|
(iternextfunc)chain_next, /* tp_iternext */
|
||||||
0, /* tp_methods */
|
0, /* tp_methods */
|
||||||
0, /* tp_members */
|
0, /* tp_members */
|
||||||
0, /* tp_getset */
|
0, /* tp_getset */
|
||||||
|
@ -946,7 +1120,7 @@ PyTypeObject times_type = {
|
||||||
0, /* tp_dictoffset */
|
0, /* tp_dictoffset */
|
||||||
0, /* tp_init */
|
0, /* tp_init */
|
||||||
PyType_GenericAlloc, /* tp_alloc */
|
PyType_GenericAlloc, /* tp_alloc */
|
||||||
times_new, /* tp_new */
|
chain_new, /* tp_new */
|
||||||
PyObject_GC_Del, /* tp_free */
|
PyObject_GC_Del, /* tp_free */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1544,6 +1718,7 @@ PyTypeObject izip_type = {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
PyObject *element;
|
PyObject *element;
|
||||||
|
long cnt;
|
||||||
} repeatobject;
|
} repeatobject;
|
||||||
|
|
||||||
PyTypeObject repeat_type;
|
PyTypeObject repeat_type;
|
||||||
|
@ -1553,8 +1728,9 @@ repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
repeatobject *ro;
|
repeatobject *ro;
|
||||||
PyObject *element;
|
PyObject *element;
|
||||||
|
long cnt = -1;
|
||||||
|
|
||||||
if (!PyArg_UnpackTuple(args, "repeat", 1, 1, &element))
|
if (!PyArg_ParseTuple(args, "O|l:repeat", &element, &cnt))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ro = (repeatobject *)type->tp_alloc(type, 0);
|
ro = (repeatobject *)type->tp_alloc(type, 0);
|
||||||
|
@ -1562,6 +1738,7 @@ repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_INCREF(element);
|
Py_INCREF(element);
|
||||||
ro->element = element;
|
ro->element = element;
|
||||||
|
ro->cnt = cnt;
|
||||||
return (PyObject *)ro;
|
return (PyObject *)ro;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1584,6 +1761,10 @@ repeat_traverse(repeatobject *ro, visitproc visit, void *arg)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
repeat_next(repeatobject *ro)
|
repeat_next(repeatobject *ro)
|
||||||
{
|
{
|
||||||
|
if (ro->cnt == 0)
|
||||||
|
return NULL;
|
||||||
|
if (ro->cnt > 0)
|
||||||
|
ro->cnt--;
|
||||||
Py_INCREF(ro->element);
|
Py_INCREF(ro->element);
|
||||||
return ro->element;
|
return ro->element;
|
||||||
}
|
}
|
||||||
|
@ -1596,7 +1777,9 @@ repeat_getiter(PyObject *ro)
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(repeat_doc,
|
PyDoc_STRVAR(repeat_doc,
|
||||||
"repeat(element) -> create an iterator which returns the element endlessly.");
|
"repeat(element [,times]) -> create an iterator which returns the element\n\
|
||||||
|
for the specified number of times. If not specified, returns the element\n\
|
||||||
|
endlessly.");
|
||||||
|
|
||||||
PyTypeObject repeat_type = {
|
PyTypeObject repeat_type = {
|
||||||
PyObject_HEAD_INIT(NULL)
|
PyObject_HEAD_INIT(NULL)
|
||||||
|
@ -1651,7 +1834,8 @@ PyDoc_STRVAR(module_doc,
|
||||||
\n\
|
\n\
|
||||||
Infinite iterators:\n\
|
Infinite iterators:\n\
|
||||||
count([n]) --> n, n+1, n+2, ...\n\
|
count([n]) --> n, n+1, n+2, ...\n\
|
||||||
repeat(elem) --> elem, elem, elem, ...\n\
|
cycle(p) --> p0, p1, ... plast, p0, p1, ...\n\
|
||||||
|
repeat(elem [,n]) --> elem, elem, elem, ... endlessly or upto n times\n\
|
||||||
\n\
|
\n\
|
||||||
Iterators terminating on the shortest input sequence:\n\
|
Iterators terminating on the shortest input sequence:\n\
|
||||||
izip(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ... \n\
|
izip(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ... \n\
|
||||||
|
@ -1661,7 +1845,7 @@ islice(seq, [start,] stop [, step]) --> elements from\n\
|
||||||
seq[start:stop:step]\n\
|
seq[start:stop:step]\n\
|
||||||
imap(fun, p, q, ...) --> fun(p0, q0), fun(p1, q1), ...\n\
|
imap(fun, p, q, ...) --> fun(p0, q0), fun(p1, q1), ...\n\
|
||||||
starmap(fun, seq) --> fun(*seq[0]), fun(*seq[1]), ...\n\
|
starmap(fun, seq) --> fun(*seq[0]), fun(*seq[1]), ...\n\
|
||||||
times(n, [obj]) --> obj, obj, ... for n times. obj defaults to None\n\
|
chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ... \n\
|
||||||
takewhile(pred, seq) --> seq[0], seq[1], until pred fails\n\
|
takewhile(pred, seq) --> seq[0], seq[1], until pred fails\n\
|
||||||
dropwhile(pred, seq) --> seq[n], seq[n+1], starting when pred fails\n\
|
dropwhile(pred, seq) --> seq[n], seq[n+1], starting when pred fails\n\
|
||||||
");
|
");
|
||||||
|
@ -1674,12 +1858,13 @@ inititertools(void)
|
||||||
PyObject *m;
|
PyObject *m;
|
||||||
char *name;
|
char *name;
|
||||||
PyTypeObject *typelist[] = {
|
PyTypeObject *typelist[] = {
|
||||||
|
&cycle_type,
|
||||||
&dropwhile_type,
|
&dropwhile_type,
|
||||||
&takewhile_type,
|
&takewhile_type,
|
||||||
&islice_type,
|
&islice_type,
|
||||||
&starmap_type,
|
&starmap_type,
|
||||||
&imap_type,
|
&imap_type,
|
||||||
×_type,
|
&chain_type,
|
||||||
&ifilter_type,
|
&ifilter_type,
|
||||||
&ifilterfalse_type,
|
&ifilterfalse_type,
|
||||||
&count_type,
|
&count_type,
|
||||||
|
@ -1694,8 +1879,7 @@ inititertools(void)
|
||||||
if (PyType_Ready(typelist[i]) < 0)
|
if (PyType_Ready(typelist[i]) < 0)
|
||||||
return;
|
return;
|
||||||
name = strchr(typelist[i]->tp_name, '.') + 1;
|
name = strchr(typelist[i]->tp_name, '.') + 1;
|
||||||
if (name == NULL)
|
assert (name != NULL);
|
||||||
return;
|
|
||||||
Py_INCREF(typelist[i]);
|
Py_INCREF(typelist[i]);
|
||||||
PyModule_AddObject(m, name, (PyObject *)typelist[i]);
|
PyModule_AddObject(m, name, (PyObject *)typelist[i]);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue