I posted about this on python-ideas, and didn't get any objections
about the idea itself, so I took the opportunity to dive into the C
API and get my hands dirty. I posted the idea and patch as a report on
SF (1706256). For anyone interested at least to look over, I'm also
just including the small patch at the end of this email. Everything is
passing for me with these changes, except the inability to subclass
the partial type. I've found the current end of my abilities in
understanding how I broke that, so I'd appreciate any reaction to the
situation.

Index: Modules/_functoolsmodule.c
===================================================================
--- Modules/_functoolsmodule.c  (revision 54922)
+++ Modules/_functoolsmodule.c  (working copy)
@@ -21,6 +21,7 @@
 } partialobject;

 static PyTypeObject partial_type;
+static PyObject *partial_skip;

 static PyObject *
 partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
@@ -89,6 +90,10 @@
 {
        PyObject *ret;
        PyObject *argappl = NULL, *kwappl = NULL;
+       PyObject *ptoargscopy, *arg;
+       Py_ssize_t skip_index = 0;
+       Py_ssize_t pull_index = 0;
+       Py_ssize_t i;

        assert (PyCallable_Check(pto->fn));
        assert (PyTuple_Check(pto->args));
@@ -101,7 +106,25 @@
                argappl = pto->args;
                Py_INCREF(pto->args);
        } else {
-               argappl = PySequence_Concat(pto->args, args);
+               
+               // For each partial_skip in the pto args, replace it with a new 
arg
+               ptoargscopy = PyTuple_New(PyTuple_GET_SIZE(pto->args));
+               for (i = 0; i<PyTuple_GET_SIZE(pto->args); ++i) {
+                       arg = PyTuple_GetItem(pto->args, i);
+                       Py_XINCREF(arg);
+                       PyTuple_SetItem(ptoargscopy, i, arg);
+                       if (arg == NULL) {
+                               break;
+                       } else if (arg == partial_skip) {
+                               arg = PyTuple_GetItem(args, pull_index);
+                               Py_XINCREF(arg);
+                               PyTuple_SetItem(ptoargscopy, i, arg);
+                               pull_index += 1;
+                       }
+               }
+
+               arg = PyTuple_GetSlice(args, pull_index, 
PySequence_Length(args));
+               argappl = PySequence_Concat(ptoargscopy, arg);
                if (argappl == NULL)
                        return NULL;
        }
@@ -142,7 +165,8 @@

 PyDoc_STRVAR(partial_doc,
 "partial(func, *args, **keywords) - new function with partial application\n\
-       of the given arguments and keywords.\n");
+       of the given arguments and keywords. Pass partial.skip to any 
positional\n\
+       argument to be bound to later.");

 #define OFF(x) offsetof(partialobject, x)
 static PyMemberDef partial_memberlist[] = {
@@ -255,7 +280,7 @@
 init_functools(void)
 {
        int i;
-       PyObject *m;
+       PyObject *m, *builtins, *skip, *object;
        char *name;
        PyTypeObject *typelist[] = {
                &partial_type,
@@ -274,4 +299,16 @@
                Py_INCREF(typelist[i]);
                PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
        }
+
+       builtins = PyImport_ImportModule("__builtin__");
+       object = PyObject_GetAttrString(builtins, "object");
+       Py_DECREF(builtins);
+       skip = PyObject_CallObject(object, NULL, NULL);
+       Py_DECREF(object);
+
+       partial_type.tp_dict = PyDict_New();
+       PyDict_SetItemString(partial_type.tp_dict, "skip", skip);
+       partial_skip = skip;
+
+       // skip is not decref'ed because a reference is always held by the
static pointer.
 }


-- 
Read my blog! I depend on your acceptance of my opinion! I am interesting!
http://ironfroggy-code.blogspot.com/
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to