Issues 2186 and 2187. Move map() from itertools to builtins.

This commit is contained in:
Raymond Hettinger 2008-03-13 01:26:19 +00:00
parent 17301e9fab
commit a6c6037f88
8 changed files with 158 additions and 203 deletions

View File

@ -22,9 +22,8 @@ The tools are designed to combine readily with one another. This makes it easy
to construct more specialized tools succinctly and efficiently in pure Python.
For instance, SML provides a tabulation tool: ``tabulate(f)`` which produces a
sequence ``f(0), f(1), ...``. This toolbox provides :func:`imap` and
:func:`count` which can be combined to form ``imap(f, count())`` and produce an
equivalent result.
sequence ``f(0), f(1), ...``. But, this effect can be achieved in Python
by combining :func:`map` and :func:`count` to form ``map(f, count())``.
Likewise, the functional tools are designed to work well with the high-speed
functions provided by the :mod:`operator` module.
@ -138,7 +137,7 @@ loops that truncate the stream.
.. function:: count([n])
Make an iterator that returns consecutive integers starting with *n*. If not
specified *n* defaults to zero. Often used as an argument to :func:`imap` to
specified *n* defaults to zero. Often used as an argument to :func:`map` to
generate consecutive data points. Also, used with :func:`izip` to add sequence
numbers. Equivalent to::
@ -248,22 +247,6 @@ loops that truncate the stream.
yield x
.. function:: imap(function, *iterables)
Make an iterator that computes the function using arguments from each of the
iterables. This function is the same as the built-in :func:`map` function.
Equivalent to::
def imap(function, *iterables):
iterables = [iter(it) for it in iterables)
while True:
args = [next(it) for it in iterables]
if function is None:
yield tuple(args)
else:
yield function(*args)
.. function:: islice(iterable, [start,] stop [, step])
Make an iterator that returns selected elements from the iterable. If *start* is
@ -421,7 +404,7 @@ loops that truncate the stream.
.. function:: repeat(object[, times])
Make an iterator that returns *object* over and over again. Runs indefinitely
unless the *times* argument is specified. Used as argument to :func:`imap` for
unless the *times* argument is specified. Used as argument to :func:`map` for
invariant parameters to the called function. Also used with :func:`izip` to
create an invariant part of a tuple record. Equivalent to::
@ -437,9 +420,9 @@ loops that truncate the stream.
.. function:: starmap(function, iterable)
Make an iterator that computes the function using arguments obtained from
the iterable. Used instead of :func:`imap` when argument parameters are already
the iterable. Used instead of :func:`map` when argument parameters are already
grouped in tuples from a single iterable (the data has been "pre-zipped"). The
difference between :func:`imap` and :func:`starmap` parallels the distinction
difference between :func:`map` and :func:`starmap` parallels the distinction
between ``function(a,b)`` and ``function(*c)``. Equivalent to::
def starmap(function, iterable):
@ -507,7 +490,7 @@ can be combined. ::
Check 1202 is for $823.14
>>> import operator
>>> for cube in imap(operator.pow, range(1,5), repeat(3)):
>>> for cube in map(operator.pow, range(1,5), repeat(3)):
... print(cube)
...
1
@ -577,7 +560,7 @@ which incur interpreter overhead. ::
def tabulate(function):
"Return function(0), function(1), ..."
return imap(function, count())
return map(function, count())
def nth(iterable, n):
"Returns the nth item or raise StopIteration"
@ -603,7 +586,7 @@ which incur interpreter overhead. ::
def quantify(seq, pred=None):
"Count how many times the predicate is true in the sequence"
return sum(imap(pred, seq))
return sum(map(pred, seq))
def padnone(seq):
"""Returns the sequence elements and then returns None indefinitely.
@ -617,7 +600,7 @@ which incur interpreter overhead. ::
return chain.from_iterable(repeat(seq, n))
def dotproduct(vec1, vec2):
return sum(imap(operator.mul, vec1, vec2))
return sum(map(operator.mul, vec1, vec2))
def flatten(listOfLists):
return list(chain.from_iterable(listOfLists))

View File

@ -12,7 +12,7 @@ Functions:
import os
import stat
import warnings
from itertools import ifilterfalse, imap, izip
from itertools import ifilterfalse, izip
__all__ = ["cmp","dircmp","cmpfiles"]
@ -130,8 +130,8 @@ class dircmp:
self.right_list.sort()
def phase1(self): # Compute common names
a = dict(izip(imap(os.path.normcase, self.left_list), self.left_list))
b = dict(izip(imap(os.path.normcase, self.right_list), self.right_list))
a = dict(izip(map(os.path.normcase, self.left_list), self.left_list))
b = dict(izip(map(os.path.normcase, self.right_list), self.right_list))
self.common = list(map(a.__getitem__, filter(b.__contains__, a)))
self.left_only = list(map(a.__getitem__, ifilterfalse(b.__contains__, a)))
self.right_only = list(map(b.__getitem__, ifilterfalse(a.__contains__, b)))

View File

@ -79,10 +79,10 @@ class IterFuncStop:
def __next__(self):
raise StopIteration
from itertools import chain, imap
from itertools import chain, map
def itermulti(seqn):
'Test multiple tiers of iterators'
return chain(imap(lambda x:x, iterfunc(IterGen(Sequence(seqn)))))
return chain(map(lambda x:x, iterfunc(IterGen(Sequence(seqn)))))
class CommonTest(unittest.TestCase):
# The type to be tested

View File

@ -260,10 +260,10 @@ class S:
def __next__(self):
raise StopIteration
from itertools import chain, imap
from itertools import chain, map
def L(seqn):
'Test multiple tiers of iterators'
return chain(imap(lambda x:x, R(Ig(G(seqn)))))
return chain(map(lambda x:x, R(Ig(G(seqn)))))
class TestErrorHandling(unittest.TestCase):
# only for C implementation

View File

@ -9,6 +9,7 @@ from functools import reduce
maxsize = test_support.MAX_Py_ssize_t
minsize = -maxsize-1
ifilter = filter
imap = map
def lzip(*args):
return list(zip(*args))

View File

@ -1560,10 +1560,10 @@ class S:
def __next__(self):
raise StopIteration
from itertools import chain, imap
from itertools import chain
def L(seqn):
'Test multiple tiers of iterators'
return chain(imap(lambda x:x, R(Ig(G(seqn)))))
return chain(map(lambda x:x, R(Ig(G(seqn)))))
class TestVariousIteratorArgs(unittest.TestCase):

View File

@ -1418,155 +1418,6 @@ static PyTypeObject starmap_type = {
};
/* imap object ************************************************************/
typedef struct {
PyObject_HEAD
PyObject *iters;
PyObject *func;
} imapobject;
static PyTypeObject imap_type;
static PyObject *
imap_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *it, *iters, *func;
imapobject *lz;
Py_ssize_t numargs, i;
if (type == &imap_type && !_PyArg_NoKeywords("imap()", kwds))
return NULL;
numargs = PyTuple_Size(args);
if (numargs < 2) {
PyErr_SetString(PyExc_TypeError,
"imap() must have at least two arguments.");
return NULL;
}
iters = PyTuple_New(numargs-1);
if (iters == NULL)
return NULL;
for (i=1 ; i<numargs ; i++) {
/* Get iterator. */
it = PyObject_GetIter(PyTuple_GET_ITEM(args, i));
if (it == NULL) {
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(iters);
return NULL;
}
lz->iters = iters;
func = PyTuple_GET_ITEM(args, 0);
Py_INCREF(func);
lz->func = func;
return (PyObject *)lz;
}
static void
imap_dealloc(imapobject *lz)
{
PyObject_GC_UnTrack(lz);
Py_XDECREF(lz->iters);
Py_XDECREF(lz->func);
Py_TYPE(lz)->tp_free(lz);
}
static int
imap_traverse(imapobject *lz, visitproc visit, void *arg)
{
Py_VISIT(lz->iters);
Py_VISIT(lz->func);
return 0;
}
static PyObject *
imap_next(imapobject *lz)
{
PyObject *val;
PyObject *argtuple;
PyObject *result;
Py_ssize_t numargs, i;
numargs = PyTuple_Size(lz->iters);
argtuple = PyTuple_New(numargs);
if (argtuple == NULL)
return NULL;
for (i=0 ; i<numargs ; i++) {
val = PyIter_Next(PyTuple_GET_ITEM(lz->iters, i));
if (val == NULL) {
Py_DECREF(argtuple);
return NULL;
}
PyTuple_SET_ITEM(argtuple, i, val);
}
result = PyObject_Call(lz->func, argtuple, NULL);
Py_DECREF(argtuple);
return result;
}
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. Stops when the shortest iterable is exhausted.");
static PyTypeObject imap_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"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 */
PyObject_SelfIter, /* 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 */
0, /* tp_alloc */
imap_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
};
/* chain object ************************************************************/
typedef struct {
@ -3068,7 +2919,6 @@ izip_longest(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ... \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\
starmap(fun, seq) --> fun(*seq[0]), fun(*seq[1]), ...\n\
tee(it, n=2) --> (it1, it2 , ... itn) splits one iterator into n\n\
chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ... \n\
@ -3096,7 +2946,6 @@ inititertools(void)
&takewhile_type,
&islice_type,
&starmap_type,
&imap_type,
&chain_type,
&ifilterfalse_type,
&count_type,

View File

@ -864,31 +864,153 @@ Return the identity of an object. This is guaranteed to be unique among\n\
simultaneously existing objects. (Hint: it's the object's memory address.)");
/* map object ************************************************************/
typedef struct {
PyObject_HEAD
PyObject *iters;
PyObject *func;
} mapobject;
PyTypeObject PyMap_Type;
static PyObject *
builtin_map(PyObject *self, PyObject *args)
map_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *itertools, *imap, *result;
itertools = PyImport_ImportModuleNoBlock("itertools");
if (itertools == NULL)
PyObject *it, *iters, *func;
mapobject *lz;
Py_ssize_t numargs, i;
if (type == &PyMap_Type && !_PyArg_NoKeywords("map()", kwds))
return NULL;
imap = PyObject_GetAttrString(itertools, "imap");
Py_DECREF(itertools);
if (imap == NULL)
numargs = PyTuple_Size(args);
if (numargs < 2) {
PyErr_SetString(PyExc_TypeError,
"map() must have at least two arguments.");
return NULL;
result = PyObject_Call(imap, args, NULL);
Py_DECREF(imap);
}
iters = PyTuple_New(numargs-1);
if (iters == NULL)
return NULL;
for (i=1 ; i<numargs ; i++) {
/* Get iterator. */
it = PyObject_GetIter(PyTuple_GET_ITEM(args, i));
if (it == NULL) {
Py_DECREF(iters);
return NULL;
}
PyTuple_SET_ITEM(iters, i-1, it);
}
/* create mapobject structure */
lz = (mapobject *)type->tp_alloc(type, 0);
if (lz == NULL) {
Py_DECREF(iters);
return NULL;
}
lz->iters = iters;
func = PyTuple_GET_ITEM(args, 0);
Py_INCREF(func);
lz->func = func;
return (PyObject *)lz;
}
static void
map_dealloc(mapobject *lz)
{
PyObject_GC_UnTrack(lz);
Py_XDECREF(lz->iters);
Py_XDECREF(lz->func);
Py_TYPE(lz)->tp_free(lz);
}
static int
map_traverse(mapobject *lz, visitproc visit, void *arg)
{
Py_VISIT(lz->iters);
Py_VISIT(lz->func);
return 0;
}
static PyObject *
map_next(mapobject *lz)
{
PyObject *val;
PyObject *argtuple;
PyObject *result;
Py_ssize_t numargs, i;
numargs = PyTuple_Size(lz->iters);
argtuple = PyTuple_New(numargs);
if (argtuple == NULL)
return NULL;
for (i=0 ; i<numargs ; i++) {
val = PyIter_Next(PyTuple_GET_ITEM(lz->iters, i));
if (val == NULL) {
Py_DECREF(argtuple);
return NULL;
}
PyTuple_SET_ITEM(argtuple, i, val);
}
result = PyObject_Call(lz->func, argtuple, NULL);
Py_DECREF(argtuple);
return result;
}
PyDoc_STRVAR(map_doc,
"map(function, iterable[, iterable, ...]) -> iterator\n\
"map(func, *iterables) --> map object\n\
\n\
Return an iterator yielding the results of applying the function to the\n\
items of the argument iterables(s). If more than one iterable is given,\n\
the function is called with an argument list consisting of the\n\
corresponding item of each iterable, until an iterable is exhausted.\n\
(This is identical to itertools.imap().)");
Make an iterator that computes the function using arguments from\n\
each of the iterables. Stops when the shortest iterable is exhausted.");
PyTypeObject PyMap_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"map", /* tp_name */
sizeof(mapobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)map_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 */
map_doc, /* tp_doc */
(traverseproc)map_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)map_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 */
map_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
};
static PyObject *
builtin_next(PyObject *self, PyObject *args)
@ -1893,7 +2015,6 @@ static PyMethodDef builtin_methods[] = {
{"iter", builtin_iter, METH_VARARGS, iter_doc},
{"len", builtin_len, METH_O, len_doc},
{"locals", (PyCFunction)builtin_locals, METH_NOARGS, locals_doc},
{"map", builtin_map, METH_VARARGS, map_doc},
{"max", (PyCFunction)builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc},
{"min", (PyCFunction)builtin_min, METH_VARARGS | METH_KEYWORDS, min_doc},
{"next", (PyCFunction)builtin_next, METH_VARARGS, next_doc},
@ -1965,6 +2086,7 @@ _PyBuiltin_Init(void)
SETBUILTIN("property", &PyProperty_Type);
SETBUILTIN("int", &PyLong_Type);
SETBUILTIN("list", &PyList_Type);
SETBUILTIN("map", &PyMap_Type);
SETBUILTIN("object", &PyBaseObject_Type);
SETBUILTIN("range", &PyRange_Type);
SETBUILTIN("reversed", &PyReversed_Type);