Commit 4c350ca0 authored by Raymond Hettinger's avatar Raymond Hettinger

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

parent a88d4c7b
...@@ -22,9 +22,8 @@ The tools are designed to combine readily with one another. This makes it easy ...@@ -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. to construct more specialized tools succinctly and efficiently in pure Python.
For instance, SML provides a tabulation tool: ``tabulate(f)`` which produces a For instance, SML provides a tabulation tool: ``tabulate(f)`` which produces a
sequence ``f(0), f(1), ...``. This toolbox provides :func:`imap` and sequence ``f(0), f(1), ...``. But, this effect can be achieved in Python
:func:`count` which can be combined to form ``imap(f, count())`` and produce an by combining :func:`map` and :func:`count` to form ``map(f, count())``.
equivalent result.
Likewise, the functional tools are designed to work well with the high-speed Likewise, the functional tools are designed to work well with the high-speed
functions provided by the :mod:`operator` module. functions provided by the :mod:`operator` module.
...@@ -138,7 +137,7 @@ loops that truncate the stream. ...@@ -138,7 +137,7 @@ loops that truncate the stream.
.. function:: count([n]) .. function:: count([n])
Make an iterator that returns consecutive integers starting with *n*. If not 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 generate consecutive data points. Also, used with :func:`izip` to add sequence
numbers. Equivalent to:: numbers. Equivalent to::
...@@ -248,22 +247,6 @@ loops that truncate the stream. ...@@ -248,22 +247,6 @@ loops that truncate the stream.
yield x 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]) .. function:: islice(iterable, [start,] stop [, step])
Make an iterator that returns selected elements from the iterable. If *start* is Make an iterator that returns selected elements from the iterable. If *start* is
...@@ -421,7 +404,7 @@ loops that truncate the stream. ...@@ -421,7 +404,7 @@ loops that truncate the stream.
.. function:: repeat(object[, times]) .. function:: repeat(object[, times])
Make an iterator that returns *object* over and over again. Runs indefinitely 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 invariant parameters to the called function. Also used with :func:`izip` to
create an invariant part of a tuple record. Equivalent to:: create an invariant part of a tuple record. Equivalent to::
...@@ -437,9 +420,9 @@ loops that truncate the stream. ...@@ -437,9 +420,9 @@ loops that truncate the stream.
.. function:: starmap(function, iterable) .. function:: starmap(function, iterable)
Make an iterator that computes the function using arguments obtained from 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 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:: between ``function(a,b)`` and ``function(*c)``. Equivalent to::
def starmap(function, iterable): def starmap(function, iterable):
...@@ -507,7 +490,7 @@ can be combined. :: ...@@ -507,7 +490,7 @@ can be combined. ::
Check 1202 is for $823.14 Check 1202 is for $823.14
>>> import operator >>> 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) ... print(cube)
... ...
1 1
...@@ -577,7 +560,7 @@ which incur interpreter overhead. :: ...@@ -577,7 +560,7 @@ which incur interpreter overhead. ::
def tabulate(function): def tabulate(function):
"Return function(0), function(1), ..." "Return function(0), function(1), ..."
return imap(function, count()) return map(function, count())
def nth(iterable, n): def nth(iterable, n):
"Returns the nth item or raise StopIteration" "Returns the nth item or raise StopIteration"
...@@ -603,7 +586,7 @@ which incur interpreter overhead. :: ...@@ -603,7 +586,7 @@ which incur interpreter overhead. ::
def quantify(seq, pred=None): def quantify(seq, pred=None):
"Count how many times the predicate is true in the sequence" "Count how many times the predicate is true in the sequence"
return sum(imap(pred, seq)) return sum(map(pred, seq))
def padnone(seq): def padnone(seq):
"""Returns the sequence elements and then returns None indefinitely. """Returns the sequence elements and then returns None indefinitely.
...@@ -617,7 +600,7 @@ which incur interpreter overhead. :: ...@@ -617,7 +600,7 @@ which incur interpreter overhead. ::
return chain.from_iterable(repeat(seq, n)) return chain.from_iterable(repeat(seq, n))
def dotproduct(vec1, vec2): def dotproduct(vec1, vec2):
return sum(imap(operator.mul, vec1, vec2)) return sum(map(operator.mul, vec1, vec2))
def flatten(listOfLists): def flatten(listOfLists):
return list(chain.from_iterable(listOfLists)) return list(chain.from_iterable(listOfLists))
......
...@@ -12,7 +12,7 @@ Functions: ...@@ -12,7 +12,7 @@ Functions:
import os import os
import stat import stat
import warnings import warnings
from itertools import ifilterfalse, imap, izip from itertools import ifilterfalse, izip
__all__ = ["cmp","dircmp","cmpfiles"] __all__ = ["cmp","dircmp","cmpfiles"]
...@@ -130,8 +130,8 @@ class dircmp: ...@@ -130,8 +130,8 @@ class dircmp:
self.right_list.sort() self.right_list.sort()
def phase1(self): # Compute common names def phase1(self): # Compute common names
a = dict(izip(imap(os.path.normcase, self.left_list), self.left_list)) a = dict(izip(map(os.path.normcase, self.left_list), self.left_list))
b = dict(izip(imap(os.path.normcase, self.right_list), self.right_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.common = list(map(a.__getitem__, filter(b.__contains__, a)))
self.left_only = list(map(a.__getitem__, ifilterfalse(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))) self.right_only = list(map(b.__getitem__, ifilterfalse(a.__contains__, b)))
......
...@@ -79,10 +79,10 @@ class IterFuncStop: ...@@ -79,10 +79,10 @@ class IterFuncStop:
def __next__(self): def __next__(self):
raise StopIteration raise StopIteration
from itertools import chain, imap from itertools import chain, map
def itermulti(seqn): def itermulti(seqn):
'Test multiple tiers of iterators' '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): class CommonTest(unittest.TestCase):
# The type to be tested # The type to be tested
......
...@@ -260,10 +260,10 @@ class S: ...@@ -260,10 +260,10 @@ class S:
def __next__(self): def __next__(self):
raise StopIteration raise StopIteration
from itertools import chain, imap from itertools import chain, map
def L(seqn): def L(seqn):
'Test multiple tiers of iterators' '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): class TestErrorHandling(unittest.TestCase):
# only for C implementation # only for C implementation
......
...@@ -9,6 +9,7 @@ from functools import reduce ...@@ -9,6 +9,7 @@ from functools import reduce
maxsize = test_support.MAX_Py_ssize_t maxsize = test_support.MAX_Py_ssize_t
minsize = -maxsize-1 minsize = -maxsize-1
ifilter = filter ifilter = filter
imap = map
def lzip(*args): def lzip(*args):
return list(zip(*args)) return list(zip(*args))
......
...@@ -1560,10 +1560,10 @@ class S: ...@@ -1560,10 +1560,10 @@ class S:
def __next__(self): def __next__(self):
raise StopIteration raise StopIteration
from itertools import chain, imap from itertools import chain
def L(seqn): def L(seqn):
'Test multiple tiers of iterators' '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): class TestVariousIteratorArgs(unittest.TestCase):
......
...@@ -1418,155 +1418,6 @@ static PyTypeObject starmap_type = { ...@@ -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 ************************************************************/ /* chain object ************************************************************/
typedef struct { typedef struct {
...@@ -3068,7 +2919,6 @@ izip_longest(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ... \n\ ...@@ -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\ ifilterfalse(pred, seq) --> elements of seq where pred(elem) is False\n\
islice(seq, [start,] stop [, step]) --> elements from\n\ 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\
starmap(fun, seq) --> fun(*seq[0]), fun(*seq[1]), ...\n\ starmap(fun, seq) --> fun(*seq[0]), fun(*seq[1]), ...\n\
tee(it, n=2) --> (it1, it2 , ... itn) splits one iterator into n\n\ tee(it, n=2) --> (it1, it2 , ... itn) splits one iterator into n\n\
chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ... \n\ chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ... \n\
...@@ -3096,7 +2946,6 @@ inititertools(void) ...@@ -3096,7 +2946,6 @@ inititertools(void)
&takewhile_type, &takewhile_type,
&islice_type, &islice_type,
&starmap_type, &starmap_type,
&imap_type,
&chain_type, &chain_type,
&ifilterfalse_type, &ifilterfalse_type,
&count_type, &count_type,
......
...@@ -864,31 +864,153 @@ Return the identity of an object. This is guaranteed to be unique among\n\ ...@@ -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.)"); 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 * static PyObject *
builtin_map(PyObject *self, PyObject *args) map_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
PyObject *itertools, *imap, *result; PyObject *it, *iters, *func;
itertools = PyImport_ImportModuleNoBlock("itertools"); mapobject *lz;
if (itertools == NULL) Py_ssize_t numargs, i;
if (type == &PyMap_Type && !_PyArg_NoKeywords("map()", kwds))
return NULL; return NULL;
imap = PyObject_GetAttrString(itertools, "imap");
Py_DECREF(itertools); numargs = PyTuple_Size(args);
if (imap == NULL) if (numargs < 2) {
PyErr_SetString(PyExc_TypeError,
"map() 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 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; return NULL;
result = PyObject_Call(imap, args, NULL);
Py_DECREF(imap); 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; return result;
} }
PyDoc_STRVAR(map_doc, PyDoc_STRVAR(map_doc,
"map(function, iterable[, iterable, ...]) -> iterator\n\ "map(func, *iterables) --> map object\n\
\n\ \n\
Return an iterator yielding the results of applying the function to the\n\ Make an iterator that computes the function using arguments from\n\
items of the argument iterables(s). If more than one iterable is given,\n\ each of the iterables. Stops when the shortest iterable is exhausted.");
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().)");
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 * static PyObject *
builtin_next(PyObject *self, PyObject *args) builtin_next(PyObject *self, PyObject *args)
...@@ -1893,7 +2015,6 @@ static PyMethodDef builtin_methods[] = { ...@@ -1893,7 +2015,6 @@ static PyMethodDef builtin_methods[] = {
{"iter", builtin_iter, METH_VARARGS, iter_doc}, {"iter", builtin_iter, METH_VARARGS, iter_doc},
{"len", builtin_len, METH_O, len_doc}, {"len", builtin_len, METH_O, len_doc},
{"locals", (PyCFunction)builtin_locals, METH_NOARGS, locals_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}, {"max", (PyCFunction)builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc},
{"min", (PyCFunction)builtin_min, METH_VARARGS | METH_KEYWORDS, min_doc}, {"min", (PyCFunction)builtin_min, METH_VARARGS | METH_KEYWORDS, min_doc},
{"next", (PyCFunction)builtin_next, METH_VARARGS, next_doc}, {"next", (PyCFunction)builtin_next, METH_VARARGS, next_doc},
...@@ -1965,6 +2086,7 @@ _PyBuiltin_Init(void) ...@@ -1965,6 +2086,7 @@ _PyBuiltin_Init(void)
SETBUILTIN("property", &PyProperty_Type); SETBUILTIN("property", &PyProperty_Type);
SETBUILTIN("int", &PyLong_Type); SETBUILTIN("int", &PyLong_Type);
SETBUILTIN("list", &PyList_Type); SETBUILTIN("list", &PyList_Type);
SETBUILTIN("map", &PyMap_Type);
SETBUILTIN("object", &PyBaseObject_Type); SETBUILTIN("object", &PyBaseObject_Type);
SETBUILTIN("range", &PyRange_Type); SETBUILTIN("range", &PyRange_Type);
SETBUILTIN("reversed", &PyReversed_Type); SETBUILTIN("reversed", &PyReversed_Type);
......
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