[Patches] Proposal To Modifying Map Function in 1.6

Zaur Shibzoukhov sz@zmail.ru
Fri, 14 Apr 2000 18:35:52 +0400


Proposal To Modifying Map Function in 1.6
-----------------------------------------

map(func, List_1, List_2, ..., List_n) use the following rule now:

    if len(List_i) < max(len(List_1),...,len(List_n)) then
        List_i[Ni]=None, List_i[Ni+1]=None, ...
            Ni=len(List_i)

I propose to change this rule to another:

    if len(List_i) < max(len(List_1),...,len(List_n)) then			
        List_i[j]=List_i[j (mod Ni)], List_i[j]=List_i[j+1 (mod Ni)],
...       (*)
            Ni=len(List_i)

Why?
Main reason: I can't use map without lambda expression in the following
common case:
   map(func, List, arg ) (1) 
or
   map(func, arg, List)  (2)
where
   func -- function with two arguments, arg -- not sequense.
Now I must do
   map(lambda x,y=arg: func(x,y), List) (1')
or
   map(lambda y,x=arg: func(x,y), List) (2')

With rule (*) I can write:
   map(func, List, [arg])

After this change I also can repeat lists of smaller length in map's
arguments.
I think that it can improve functionality of map.

For example:

    Ls=[list_1, ..., list_N]
    map(append, Ls, [a,b]) ->
          [list_1+[a],list_2+[b],list_3+[a],,list_4+[b], ...]

    or

    Ls = [func_1, ..., func_N]
    map(apply, Ls, [args])
        instead of
    map(lambda f,args=args: apply(f, args), Ls)

    and others ...

This modification allow to prevent using lambda expression
in map calls in some cases.

Here is an easy "patch" to map (for source of Python 1.5.2)

static PyObject *
builtin_map(self, args)
        PyObject *self;
        PyObject *args;
{
        typedef struct {
                PyObject *seq;
                PySequenceMethods *sqf;
                int len;
        } sequence;

        PyObject *func, *result;
        sequence *seqs = NULL, *sqp;
        int n, len;
        register int i, j;

        n = PyTuple_Size(args);
        if (n < 2) {
                PyErr_SetString(PyExc_TypeError,
                                "map() requires at least two args");
                return NULL;
        }

        func = PyTuple_GetItem(args, 0);
        n--;

        if (func == Py_None && n == 1) {
                /* map(None, S) is the same as list(S). */
                return PySequence_List(PyTuple_GetItem(args, 1));
        }

        if ((seqs = PyMem_NEW(sequence, n)) == NULL) {
                PyErr_NoMemory();
                goto Fail_2;
        }

        for (len = 0, i = 0, sqp = seqs; i < n; ++i, ++sqp) {
                int curlen;
                PySequenceMethods *sqf;
        
                if ((sqp->seq = PyTuple_GetItem(args, i + 1)) == NULL)
                        goto Fail_2;

                sqp->sqf = sqf = sqp->seq->ob_type->tp_as_sequence;
                if (sqf == NULL ||
                    sqf->sq_length == NULL ||
                    sqf->sq_item == NULL)
                {
                        static char errmsg[] =
                            "argument %d to map() must be a sequence
object";
                        char errbuf[sizeof(errmsg) + 25];

                        sprintf(errbuf, errmsg, i+2);
                        PyErr_SetString(PyExc_TypeError, errbuf);
                        goto Fail_2;
                }

                if ((curlen = sqp->len =
(*sqp->sqf->sq_length)(sqp->seq)) < 0)
                        goto Fail_2;

                if (curlen > len)
                        len = curlen;
        }

        if ((result = (PyObject *) PyList_New(len)) == NULL)
                goto Fail_2;

        for (i = 0; ; ++i) {
                PyObject *alist, *item=NULL, *value;
                int any = 0;

                if (func == Py_None && n == 1)
                        alist = NULL;
                else {
                        if ((alist = PyTuple_New(n)) == NULL)
                                goto Fail_1;
                }

                for (j = 0, sqp = seqs; j < n; ++j, ++sqp) {
                         if (sqp->len < 0) {
                   -            Py_INCREF(Py_None);
                   -            item = Py_None;
                   +            item = (*sqp->sqf->sq_item)(sqp->seq, i
% - sqp->len);
                         }
                         else {
                                item = (*sqp->sqf->sq_item)(sqp->seq,
i);
                                if (item == NULL) {
                                       if (PyErr_ExceptionMatches(
                                               PyExc_IndexError))
                                       {
                                               PyErr_Clear();
                   -                           Py_INCREF(Py_None);
                   -                           item = Py_None;
                   +                           item =
(*sqp->sqf->sq_item)(sqp->seq, i % sqp->len);
                   -                           sqp->len = -1; 
                   +                           sqp->len = - sqp->len; 
                                       }
                                       else {
                                               goto Fail_0;
                                       }
                                }
                                else
                                        any = 1;
                        }
                        if (!alist)
                                break;
                        if (PyTuple_SetItem(alist, j, item) < 0) {
                                Py_DECREF(item);
                                goto Fail_0;
                        }
                        continue;

                Fail_0:
                        Py_XDECREF(alist);
                        goto Fail_1;
                }

                if (!alist)
                        alist = item;

                if (!any) {
                        Py_DECREF(alist);
                        break;
                }

                if (func == Py_None)
                        value = alist;
                else {
                        value = PyEval_CallObject(func, alist);
                        Py_DECREF(alist);
                        if (value == NULL)
                                goto Fail_1;
                }
                if (i >= len) {
                        int status = PyList_Append(result, value);
                        Py_DECREF(value);
                        if (status < 0)
                                goto Fail_1;
                }
                else {
                        if (PyList_SetItem(result, i, value) < 0)
                                goto Fail_1;
                }
        }

        if (i < len && PyList_SetSlice(result, i, len, NULL) < 0)
                goto Fail_1;

        PyMem_DEL(seqs);
        return result;

Fail_1:
        Py_DECREF(result);
Fail_2:
        if (seqs) PyMem_DEL(seqs);
        return NULL;
}


Zaur Shibzoukhov
sz@zmail.ru


        
-----------------------------------------------
Get Your e-mail at http://zmail.ru