diff -r d9dbca5b6666 Lib/test/test_functools.py --- a/Lib/test/test_functools.py Sat Jan 09 19:50:50 2010 +0100 +++ b/Lib/test/test_functools.py Sat Jan 09 21:48:20 2010 +0100 @@ -151,6 +151,18 @@ f_copy = pickle.loads(pickle.dumps(f)) self.assertEqual(signature(f), signature(f_copy)) + def class_capture(self, *args, **kwargs): + return self, args, kwargs + + partial_class_capture = thetype(class_capture, 1, a=10) + partial_partial_class_capture = thetype(partial_class_capture, b=20) + + def test_partial_as_method(self): + self.assertEqual(self.partial_class_capture(2), + (self, (1, 2), {'a': 10})) + self.assertEqual(self.partial_partial_class_capture(2, c=30), + (self, (1, 2), {'a': 10, 'b': 20, 'c': 30})) + class PartialSubclass(functools.partial): pass diff -r d9dbca5b6666 Modules/_functoolsmodule.c --- a/Modules/_functoolsmodule.c Sat Jan 09 19:50:50 2010 +0100 +++ b/Modules/_functoolsmodule.c Sat Jan 09 21:48:20 2010 +0100 @@ -162,6 +162,58 @@ Py_TYPE(pto)->tp_free(pto); } +PyObject * +_partial_merge_args(partialobject *pto, PyObject *args) +{ + PyObject *argappl = NULL; + + assert (PyTuple_Check(pto->args)); + + if (PyTuple_GET_SIZE(pto->args) == 0) { + argappl = args; + Py_XINCREF(args); + } else if (args == NULL || PyTuple_GET_SIZE(args) == 0) { + argappl = pto->args; + Py_INCREF(pto->args); + } else { + argappl = PySequence_Concat(pto->args, args); + if (argappl == NULL) + return NULL; + } + if (argappl == NULL) { + return PyTuple_New(0); + } + return argappl; +} + +PyObject * +_partial_merge_kwargs(partialobject *pto, PyObject *kw) +{ + PyObject *kwappl = NULL; + + assert (pto->kw == Py_None || PyDict_Check(pto->kw)); + + if (pto->kw == Py_None) { + kwappl = kw; + Py_XINCREF(kw); + } else { + kwappl = PyDict_Copy(pto->kw); + if (kwappl == NULL) { + return NULL; + } + if (kw != NULL) { + if (PyDict_Merge(kwappl, kw, 1) != 0) { + Py_DECREF(kwappl); + return NULL; + } + } + } + if (kwappl == NULL) { + return PyDict_New(); + } + return kwappl; +} + static PyObject * partial_call(partialobject *pto, PyObject *args, PyObject *kw) { @@ -169,37 +221,15 @@ PyObject *argappl = NULL, *kwappl = NULL; assert (PyCallable_Check(pto->fn)); - assert (PyTuple_Check(pto->args)); - assert (pto->kw == Py_None || PyDict_Check(pto->kw)); - if (PyTuple_GET_SIZE(pto->args) == 0) { - argappl = args; - Py_INCREF(args); - } else if (PyTuple_GET_SIZE(args) == 0) { - argappl = pto->args; - Py_INCREF(pto->args); - } else { - argappl = PySequence_Concat(pto->args, args); - if (argappl == NULL) - return NULL; + argappl = _partial_merge_args(pto, args); + if (argappl == NULL) { + return NULL; } - - if (pto->kw == Py_None) { - kwappl = kw; - Py_XINCREF(kw); - } else { - kwappl = PyDict_Copy(pto->kw); - if (kwappl == NULL) { - Py_DECREF(argappl); - return NULL; - } - if (kw != NULL) { - if (PyDict_Merge(kwappl, kw, 1) != 0) { - Py_DECREF(argappl); - Py_DECREF(kwappl); - return NULL; - } - } + kwappl = _partial_merge_kwargs(pto, kw); + if (kwappl == NULL) { + Py_DECREF(argappl); + return NULL; } ret = PyObject_Call(pto->fn, argappl, kwappl); @@ -315,6 +345,67 @@ Py_RETURN_NONE; } +static PyObject * +partial_descr_get(partialobject *pto, PyObject *obj, PyObject *type) +{ + PyObject *tpl = NULL, *tmp = NULL, *argappl = NULL, *kw = NULL, *fn = NULL; + partialobject *current = NULL; + + current = pto; + Py_INCREF(pto); + + if (obj == Py_None) { + obj = NULL; + } + + do { + Py_XDECREF(fn); + fn = current->fn; + Py_INCREF(fn); + + tmp = _partial_merge_args(current, argappl); + if (tmp == NULL) goto fail; + Py_XDECREF(argappl); + argappl = tmp; + + tmp = _partial_merge_kwargs(current, kw); + if (tmp == NULL) goto fail; + Py_XDECREF(kw); + kw = tmp; + + tmp = NULL; + + Py_DECREF(current); + current = NULL; + if (Py_TYPE(fn) == &partial_type) { + current = (partialobject *)fn; + Py_INCREF(current); + } + + } while (current != NULL); + + if ((tpl = PyTuple_New(2)) == NULL) { + goto fail; + } + PyTuple_SetItem(tpl, 0, fn); + Py_INCREF(fn); + PyTuple_SetItem(tpl, 1, obj); + Py_XINCREF(obj); + + tmp = PySequence_Concat(tpl, argappl); + if (tmp == NULL) goto fail; + Py_XDECREF(argappl); + argappl = tmp; + + return (PyObject *)partial_new(&partial_type, argappl, kw); + +fail: + Py_XDECREF(tpl); + Py_XDECREF(fn); + Py_XDECREF(current); + return NULL; +} + static PyMethodDef partial_methods[] = { {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS}, {"__setstate__", (PyCFunction)partial_setstate, METH_VARARGS}, @@ -356,7 +447,7 @@ partial_getsetlist, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ - 0, /* tp_descr_get */ + (descrgetfunc)partial_descr_get,/* tp_descr_get */ 0, /* tp_descr_set */ offsetof(partialobject, dict), /* tp_dictoffset */ 0, /* tp_init */

AltStyle によって変換されたページ (->オリジナル) /