diff -r 0eeb39fc8ff5 Doc/library/operator.rst --- a/Doc/library/operator.rst Tue Dec 01 19:59:53 2015 +1100 +++ b/Doc/library/operator.rst Tue Dec 01 18:05:26 2015 -0500 @@ -349,6 +349,10 @@ def methodcaller(name, *args, **kwargs): def caller(obj): return getattr(obj, name)(*args, **kwargs) + + caller.name = name + caller.args = args + caller.keywords = kwargs return caller diff -r 0eeb39fc8ff5 Lib/operator.py --- a/Lib/operator.py Tue Dec 01 19:59:53 2015 +1100 +++ b/Lib/operator.py Tue Dec 01 18:05:26 2015 -0500 @@ -313,6 +313,21 @@ self._args = args[2:] self._kwargs = kwargs + @property + def name(self): + "The name of the method to call." + return self._name + + @property + def args(self): + "The positional arguments to pass to the method." + return self._args + + @property + def keywords(self): + "The keyword arguments to pass to the method." + return self._kwargs + def __call__(self, obj): return getattr(obj, self._name)(*self._args, **self._kwargs) diff -r 0eeb39fc8ff5 Lib/test/test_operator.py --- a/Lib/test/test_operator.py Tue Dec 01 19:59:53 2015 +1100 +++ b/Lib/test/test_operator.py Tue Dec 01 18:05:26 2015 -0500 @@ -419,6 +419,16 @@ f = operator.methodcaller('baz', name='spam', self='eggs') self.assertEqual(f(a), ('spam', 'eggs')) + f = operator.methodcaller('spam', 1, 2, a=3, b=4) + self.assertEqual(f.name, 'spam') + self.assertEqual(f.args, (1, 2)) + self.assertEqual(f.keywords, {'a':3, 'b': 4}) + + f = operator.methodcaller('eggs', 1, 2) + self.assertEqual(f.name, 'eggs') + self.assertEqual(f.args, (1, 2)) + self.assertEqual(f.keywords, {}) + def test_inplace(self): operator = self.module class C(object): diff -r 0eeb39fc8ff5 Modules/_operator.c --- a/Modules/_operator.c Tue Dec 01 19:59:53 2015 +1100 +++ b/Modules/_operator.c Tue Dec 01 18:05:26 2015 -0500 @@ -1,5 +1,6 @@ #include "Python.h" +#include PyDoc_STRVAR(operator_doc, "Operator interface.\n\ @@ -1134,6 +1135,45 @@ reduce_doc}, {NULL} }; + +PyDoc_STRVAR(methodcaller_name_doc, + "The name of the method to call."); +PyDoc_STRVAR(methodcaller_args_doc, + "The positional arguments to pass to the method."); + +static PyMemberDef methodcaller_members[] = { + {"name", T_OBJECT, offsetof(methodcallerobject, name), + READONLY, methodcaller_name_doc}, + {"args", T_OBJECT, offsetof(methodcallerobject, args), + READONLY, methodcaller_args_doc}, + {NULL}, +}; + +static PyObject * +methodcaller_keyword_get(methodcallerobject *self, void *_) +{ + if (!self->kwds) { + if (!(self->kwds = PyDict_New())) { + return NULL; + } + } + + Py_INCREF(self->kwds); + return self->kwds; +} + +PyDoc_STRVAR(methodcaller_kwds_doc, + "The keyword arguments to pass to the method."); + +static PyGetSetDef methodcaller_getsets[] = { + {"keywords", + (getter) methodcaller_keyword_get, + NULL, + methodcaller_kwds_doc, + NULL}, + {NULL}, +}; + PyDoc_STRVAR(methodcaller_doc, "methodcaller(name, ...) --> methodcaller object\n\ \n\ @@ -1148,7 +1188,7 @@ sizeof(methodcallerobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - (destructor)methodcaller_dealloc, /* tp_dealloc */ + (destructor)methodcaller_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -1172,8 +1212,8 @@ 0, /* tp_iter */ 0, /* tp_iternext */ methodcaller_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ + methodcaller_members, /* tp_members */ + methodcaller_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */